editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18mod code_context_menus;
   19pub mod commit_tooltip;
   20pub mod display_map;
   21mod editor_settings;
   22mod editor_settings_controls;
   23mod element;
   24mod git;
   25mod highlight_matching_bracket;
   26mod hover_links;
   27mod hover_popover;
   28mod indent_guides;
   29mod inlay_hint_cache;
   30pub mod items;
   31mod linked_editing_ranges;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod editor_tests;
   44#[cfg(test)]
   45mod inline_completion_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50pub(crate) use actions::*;
   51pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   52use aho_corasick::AhoCorasick;
   53use anyhow::{anyhow, Context as _, Result};
   54use blink_manager::BlinkManager;
   55use buffer_diff::{DiffHunkSecondaryStatus, DiffHunkStatus};
   56use client::{Collaborator, ParticipantIndex};
   57use clock::ReplicaId;
   58use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   59use convert_case::{Case, Casing};
   60use display_map::*;
   61pub use display_map::{DisplayPoint, FoldPlaceholder};
   62pub use editor_settings::{
   63    CurrentLineHighlight, EditorSettings, ScrollBeyondLastLine, SearchSettings, ShowScrollbar,
   64};
   65pub use editor_settings_controls::*;
   66use element::{layout_line, AcceptEditPredictionBinding, LineWithInvisibles, PositionMap};
   67pub use element::{
   68    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   69};
   70use futures::{
   71    future::{self, Shared},
   72    FutureExt,
   73};
   74use fuzzy::StringMatchCandidate;
   75
   76use ::git::{status::FileStatus, Restore};
   77use code_context_menus::{
   78    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   79    CompletionsMenu, ContextMenuOrigin,
   80};
   81use git::blame::GitBlame;
   82use gpui::{
   83    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size, Action, Animation,
   84    AnimationExt, AnyElement, App, AsyncWindowContext, AvailableSpace, Background, Bounds,
   85    ClipboardEntry, ClipboardItem, Context, DispatchPhase, Edges, Entity, EntityInputHandler,
   86    EventEmitter, FocusHandle, FocusOutEvent, Focusable, FontId, FontWeight, Global,
   87    HighlightStyle, Hsla, KeyContext, Modifiers, MouseButton, MouseDownEvent, PaintQuad,
   88    ParentElement, Pixels, Render, SharedString, Size, Styled, StyledText, Subscription, Task,
   89    TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
   90    WeakEntity, WeakFocusHandle, Window,
   91};
   92use highlight_matching_bracket::refresh_matching_bracket_highlights;
   93use hover_popover::{hide_hover, HoverState};
   94use indent_guides::ActiveIndentGuidesState;
   95use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
   96pub use inline_completion::Direction;
   97use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
   98pub use items::MAX_TAB_TITLE_LEN;
   99use itertools::Itertools;
  100use language::{
  101    language_settings::{
  102        self, all_language_settings, language_settings, InlayHintSettings, RewrapBehavior,
  103    },
  104    point_from_lsp, text_diff_with_options, AutoindentMode, BracketMatch, BracketPair, Buffer,
  105    Capability, CharKind, CodeLabel, CursorShape, Diagnostic, DiffOptions, EditPredictionsMode,
  106    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  107    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  108};
  109use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange};
  110use linked_editing_ranges::refresh_linked_ranges;
  111use mouse_context_menu::MouseContextMenu;
  112use persistence::DB;
  113pub use proposed_changes_editor::{
  114    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  115};
  116use smallvec::smallvec;
  117use std::iter::Peekable;
  118use task::{ResolvedTask, TaskTemplate, TaskVariables};
  119
  120use hover_links::{find_file, HoverLink, HoveredLinkState, InlayHighlight};
  121pub use lsp::CompletionContext;
  122use lsp::{
  123    CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity, InsertTextFormat,
  124    LanguageServerId, LanguageServerName,
  125};
  126
  127use language::BufferSnapshot;
  128use movement::TextLayoutDetails;
  129pub use multi_buffer::{
  130    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, RowInfo,
  131    ToOffset, ToPoint,
  132};
  133use multi_buffer::{
  134    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  135    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  136};
  137use project::{
  138    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  139    project_settings::{GitGutterSetting, ProjectSettings},
  140    CodeAction, Completion, CompletionIntent, DocumentHighlight, InlayHint, Location, LocationLink,
  141    PrepareRenameResponse, Project, ProjectItem, ProjectTransaction, TaskSourceKind,
  142};
  143use rand::prelude::*;
  144use rpc::{proto::*, ErrorExt};
  145use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  146use selections_collection::{
  147    resolve_selections, MutableSelectionsCollection, SelectionsCollection,
  148};
  149use serde::{Deserialize, Serialize};
  150use settings::{update_settings_file, Settings, SettingsLocation, SettingsStore};
  151use smallvec::SmallVec;
  152use snippet::Snippet;
  153use std::{
  154    any::TypeId,
  155    borrow::Cow,
  156    cell::RefCell,
  157    cmp::{self, Ordering, Reverse},
  158    mem,
  159    num::NonZeroU32,
  160    ops::{ControlFlow, Deref, DerefMut, Not as _, Range, RangeInclusive},
  161    path::{Path, PathBuf},
  162    rc::Rc,
  163    sync::Arc,
  164    time::{Duration, Instant},
  165};
  166pub use sum_tree::Bias;
  167use sum_tree::TreeMap;
  168use text::{BufferId, OffsetUtf16, Rope};
  169use theme::{
  170    observe_buffer_font_size_adjustment, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme,
  171    ThemeColors, ThemeSettings,
  172};
  173use ui::{
  174    h_flex, prelude::*, ButtonSize, ButtonStyle, Disclosure, IconButton, IconName, IconSize, Key,
  175    Tooltip,
  176};
  177use util::{defer, maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
  178use workspace::{
  179    item::{ItemHandle, PreviewTabsSettings},
  180    ItemId, RestoreOnStartupBehavior,
  181};
  182use workspace::{
  183    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  184    WorkspaceSettings,
  185};
  186use workspace::{
  187    searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId,
  188};
  189use workspace::{Item as WorkspaceItem, OpenInTerminal, OpenTerminal, TabBarSettings, Toast};
  190
  191use crate::hover_links::{find_url, find_url_from_range};
  192use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  193
  194pub const FILE_HEADER_HEIGHT: u32 = 2;
  195pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  196pub const MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT: u32 = 1;
  197pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  198const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  199const MAX_LINE_LEN: usize = 1024;
  200const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  201const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  202pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  203#[doc(hidden)]
  204pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  205
  206pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  207pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  208
  209pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  210pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  211
  212const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  213    alt: true,
  214    shift: true,
  215    control: false,
  216    platform: false,
  217    function: false,
  218};
  219
  220#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  221pub enum InlayId {
  222    InlineCompletion(usize),
  223    Hint(usize),
  224}
  225
  226impl InlayId {
  227    fn id(&self) -> usize {
  228        match self {
  229            Self::InlineCompletion(id) => *id,
  230            Self::Hint(id) => *id,
  231        }
  232    }
  233}
  234
  235enum DocumentHighlightRead {}
  236enum DocumentHighlightWrite {}
  237enum InputComposition {}
  238enum SelectedTextHighlight {}
  239
  240#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  241pub enum Navigated {
  242    Yes,
  243    No,
  244}
  245
  246impl Navigated {
  247    pub fn from_bool(yes: bool) -> Navigated {
  248        if yes {
  249            Navigated::Yes
  250        } else {
  251            Navigated::No
  252        }
  253    }
  254}
  255
  256#[derive(Debug, Clone, PartialEq, Eq)]
  257enum DisplayDiffHunk {
  258    Folded {
  259        display_row: DisplayRow,
  260    },
  261    Unfolded {
  262        diff_base_byte_range: Range<usize>,
  263        display_row_range: Range<DisplayRow>,
  264        multi_buffer_range: Range<Anchor>,
  265        status: DiffHunkStatus,
  266    },
  267}
  268
  269pub fn init_settings(cx: &mut App) {
  270    EditorSettings::register(cx);
  271}
  272
  273pub fn init(cx: &mut App) {
  274    init_settings(cx);
  275
  276    workspace::register_project_item::<Editor>(cx);
  277    workspace::FollowableViewRegistry::register::<Editor>(cx);
  278    workspace::register_serializable_item::<Editor>(cx);
  279
  280    cx.observe_new(
  281        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  282            workspace.register_action(Editor::new_file);
  283            workspace.register_action(Editor::new_file_vertical);
  284            workspace.register_action(Editor::new_file_horizontal);
  285            workspace.register_action(Editor::cancel_language_server_work);
  286        },
  287    )
  288    .detach();
  289
  290    cx.on_action(move |_: &workspace::NewFile, cx| {
  291        let app_state = workspace::AppState::global(cx);
  292        if let Some(app_state) = app_state.upgrade() {
  293            workspace::open_new(
  294                Default::default(),
  295                app_state,
  296                cx,
  297                |workspace, window, cx| {
  298                    Editor::new_file(workspace, &Default::default(), window, cx)
  299                },
  300            )
  301            .detach();
  302        }
  303    });
  304    cx.on_action(move |_: &workspace::NewWindow, cx| {
  305        let app_state = workspace::AppState::global(cx);
  306        if let Some(app_state) = app_state.upgrade() {
  307            workspace::open_new(
  308                Default::default(),
  309                app_state,
  310                cx,
  311                |workspace, window, cx| {
  312                    cx.activate(true);
  313                    Editor::new_file(workspace, &Default::default(), window, cx)
  314                },
  315            )
  316            .detach();
  317        }
  318    });
  319}
  320
  321pub struct SearchWithinRange;
  322
  323trait InvalidationRegion {
  324    fn ranges(&self) -> &[Range<Anchor>];
  325}
  326
  327#[derive(Clone, Debug, PartialEq)]
  328pub enum SelectPhase {
  329    Begin {
  330        position: DisplayPoint,
  331        add: bool,
  332        click_count: usize,
  333    },
  334    BeginColumnar {
  335        position: DisplayPoint,
  336        reset: bool,
  337        goal_column: u32,
  338    },
  339    Extend {
  340        position: DisplayPoint,
  341        click_count: usize,
  342    },
  343    Update {
  344        position: DisplayPoint,
  345        goal_column: u32,
  346        scroll_delta: gpui::Point<f32>,
  347    },
  348    End,
  349}
  350
  351#[derive(Clone, Debug)]
  352pub enum SelectMode {
  353    Character,
  354    Word(Range<Anchor>),
  355    Line(Range<Anchor>),
  356    All,
  357}
  358
  359#[derive(Copy, Clone, PartialEq, Eq, Debug)]
  360pub enum EditorMode {
  361    SingleLine { auto_width: bool },
  362    AutoHeight { max_lines: usize },
  363    Full,
  364}
  365
  366#[derive(Copy, Clone, Debug)]
  367pub enum SoftWrap {
  368    /// Prefer not to wrap at all.
  369    ///
  370    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  371    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  372    GitDiff,
  373    /// Prefer a single line generally, unless an overly long line is encountered.
  374    None,
  375    /// Soft wrap lines that exceed the editor width.
  376    EditorWidth,
  377    /// Soft wrap lines at the preferred line length.
  378    Column(u32),
  379    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  380    Bounded(u32),
  381}
  382
  383#[derive(Clone)]
  384pub struct EditorStyle {
  385    pub background: Hsla,
  386    pub local_player: PlayerColor,
  387    pub text: TextStyle,
  388    pub scrollbar_width: Pixels,
  389    pub syntax: Arc<SyntaxTheme>,
  390    pub status: StatusColors,
  391    pub inlay_hints_style: HighlightStyle,
  392    pub inline_completion_styles: InlineCompletionStyles,
  393    pub unnecessary_code_fade: f32,
  394}
  395
  396impl Default for EditorStyle {
  397    fn default() -> Self {
  398        Self {
  399            background: Hsla::default(),
  400            local_player: PlayerColor::default(),
  401            text: TextStyle::default(),
  402            scrollbar_width: Pixels::default(),
  403            syntax: Default::default(),
  404            // HACK: Status colors don't have a real default.
  405            // We should look into removing the status colors from the editor
  406            // style and retrieve them directly from the theme.
  407            status: StatusColors::dark(),
  408            inlay_hints_style: HighlightStyle::default(),
  409            inline_completion_styles: InlineCompletionStyles {
  410                insertion: HighlightStyle::default(),
  411                whitespace: HighlightStyle::default(),
  412            },
  413            unnecessary_code_fade: Default::default(),
  414        }
  415    }
  416}
  417
  418pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  419    let show_background = language_settings::language_settings(None, None, cx)
  420        .inlay_hints
  421        .show_background;
  422
  423    HighlightStyle {
  424        color: Some(cx.theme().status().hint),
  425        background_color: show_background.then(|| cx.theme().status().hint_background),
  426        ..HighlightStyle::default()
  427    }
  428}
  429
  430pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  431    InlineCompletionStyles {
  432        insertion: HighlightStyle {
  433            color: Some(cx.theme().status().predictive),
  434            ..HighlightStyle::default()
  435        },
  436        whitespace: HighlightStyle {
  437            background_color: Some(cx.theme().status().created_background),
  438            ..HighlightStyle::default()
  439        },
  440    }
  441}
  442
  443type CompletionId = usize;
  444
  445pub(crate) enum EditDisplayMode {
  446    TabAccept,
  447    DiffPopover,
  448    Inline,
  449}
  450
  451enum InlineCompletion {
  452    Edit {
  453        edits: Vec<(Range<Anchor>, String)>,
  454        edit_preview: Option<EditPreview>,
  455        display_mode: EditDisplayMode,
  456        snapshot: BufferSnapshot,
  457    },
  458    Move {
  459        target: Anchor,
  460        snapshot: BufferSnapshot,
  461    },
  462}
  463
  464struct InlineCompletionState {
  465    inlay_ids: Vec<InlayId>,
  466    completion: InlineCompletion,
  467    completion_id: Option<SharedString>,
  468    invalidation_range: Range<Anchor>,
  469}
  470
  471enum EditPredictionSettings {
  472    Disabled,
  473    Enabled {
  474        show_in_menu: bool,
  475        preview_requires_modifier: bool,
  476    },
  477}
  478
  479enum InlineCompletionHighlight {}
  480
  481#[derive(Debug, Clone)]
  482struct InlineDiagnostic {
  483    message: SharedString,
  484    group_id: usize,
  485    is_primary: bool,
  486    start: Point,
  487    severity: DiagnosticSeverity,
  488}
  489
  490pub enum MenuInlineCompletionsPolicy {
  491    Never,
  492    ByProvider,
  493}
  494
  495pub enum EditPredictionPreview {
  496    /// Modifier is not pressed
  497    Inactive { released_too_fast: bool },
  498    /// Modifier pressed
  499    Active {
  500        since: Instant,
  501        previous_scroll_position: Option<ScrollAnchor>,
  502    },
  503}
  504
  505impl EditPredictionPreview {
  506    pub fn released_too_fast(&self) -> bool {
  507        match self {
  508            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  509            EditPredictionPreview::Active { .. } => false,
  510        }
  511    }
  512
  513    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  514        if let EditPredictionPreview::Active {
  515            previous_scroll_position,
  516            ..
  517        } = self
  518        {
  519            *previous_scroll_position = scroll_position;
  520        }
  521    }
  522}
  523
  524#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  525struct EditorActionId(usize);
  526
  527impl EditorActionId {
  528    pub fn post_inc(&mut self) -> Self {
  529        let answer = self.0;
  530
  531        *self = Self(answer + 1);
  532
  533        Self(answer)
  534    }
  535}
  536
  537// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  538// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  539
  540type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  541type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  542
  543#[derive(Default)]
  544struct ScrollbarMarkerState {
  545    scrollbar_size: Size<Pixels>,
  546    dirty: bool,
  547    markers: Arc<[PaintQuad]>,
  548    pending_refresh: Option<Task<Result<()>>>,
  549}
  550
  551impl ScrollbarMarkerState {
  552    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  553        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  554    }
  555}
  556
  557#[derive(Clone, Debug)]
  558struct RunnableTasks {
  559    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  560    offset: multi_buffer::Anchor,
  561    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  562    column: u32,
  563    // Values of all named captures, including those starting with '_'
  564    extra_variables: HashMap<String, String>,
  565    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  566    context_range: Range<BufferOffset>,
  567}
  568
  569impl RunnableTasks {
  570    fn resolve<'a>(
  571        &'a self,
  572        cx: &'a task::TaskContext,
  573    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  574        self.templates.iter().filter_map(|(kind, template)| {
  575            template
  576                .resolve_task(&kind.to_id_base(), cx)
  577                .map(|task| (kind.clone(), task))
  578        })
  579    }
  580}
  581
  582#[derive(Clone)]
  583struct ResolvedTasks {
  584    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  585    position: Anchor,
  586}
  587#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  588struct BufferOffset(usize);
  589
  590// Addons allow storing per-editor state in other crates (e.g. Vim)
  591pub trait Addon: 'static {
  592    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  593
  594    fn render_buffer_header_controls(
  595        &self,
  596        _: &ExcerptInfo,
  597        _: &Window,
  598        _: &App,
  599    ) -> Option<AnyElement> {
  600        None
  601    }
  602
  603    fn to_any(&self) -> &dyn std::any::Any;
  604}
  605
  606#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  607pub enum IsVimMode {
  608    Yes,
  609    No,
  610}
  611
  612/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  613///
  614/// See the [module level documentation](self) for more information.
  615pub struct Editor {
  616    focus_handle: FocusHandle,
  617    last_focused_descendant: Option<WeakFocusHandle>,
  618    /// The text buffer being edited
  619    buffer: Entity<MultiBuffer>,
  620    /// Map of how text in the buffer should be displayed.
  621    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  622    pub display_map: Entity<DisplayMap>,
  623    pub selections: SelectionsCollection,
  624    pub scroll_manager: ScrollManager,
  625    /// When inline assist editors are linked, they all render cursors because
  626    /// typing enters text into each of them, even the ones that aren't focused.
  627    pub(crate) show_cursor_when_unfocused: bool,
  628    columnar_selection_tail: Option<Anchor>,
  629    add_selections_state: Option<AddSelectionsState>,
  630    select_next_state: Option<SelectNextState>,
  631    select_prev_state: Option<SelectNextState>,
  632    selection_history: SelectionHistory,
  633    autoclose_regions: Vec<AutocloseRegion>,
  634    snippet_stack: InvalidationStack<SnippetState>,
  635    select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
  636    ime_transaction: Option<TransactionId>,
  637    active_diagnostics: Option<ActiveDiagnosticGroup>,
  638    show_inline_diagnostics: bool,
  639    inline_diagnostics_update: Task<()>,
  640    inline_diagnostics_enabled: bool,
  641    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  642    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  643
  644    // TODO: make this a access method
  645    pub project: Option<Entity<Project>>,
  646    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  647    completion_provider: Option<Box<dyn CompletionProvider>>,
  648    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  649    blink_manager: Entity<BlinkManager>,
  650    show_cursor_names: bool,
  651    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  652    pub show_local_selections: bool,
  653    mode: EditorMode,
  654    show_breadcrumbs: bool,
  655    show_gutter: bool,
  656    show_scrollbars: bool,
  657    show_line_numbers: Option<bool>,
  658    use_relative_line_numbers: Option<bool>,
  659    show_git_diff_gutter: Option<bool>,
  660    show_code_actions: Option<bool>,
  661    show_runnables: Option<bool>,
  662    show_wrap_guides: Option<bool>,
  663    show_indent_guides: Option<bool>,
  664    placeholder_text: Option<Arc<str>>,
  665    highlight_order: usize,
  666    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  667    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  668    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  669    scrollbar_marker_state: ScrollbarMarkerState,
  670    active_indent_guides_state: ActiveIndentGuidesState,
  671    nav_history: Option<ItemNavHistory>,
  672    context_menu: RefCell<Option<CodeContextMenu>>,
  673    mouse_context_menu: Option<MouseContextMenu>,
  674    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  675    signature_help_state: SignatureHelpState,
  676    auto_signature_help: Option<bool>,
  677    find_all_references_task_sources: Vec<Anchor>,
  678    next_completion_id: CompletionId,
  679    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  680    code_actions_task: Option<Task<Result<()>>>,
  681    selection_highlight_task: Option<Task<()>>,
  682    document_highlights_task: Option<Task<()>>,
  683    linked_editing_range_task: Option<Task<Option<()>>>,
  684    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  685    pending_rename: Option<RenameState>,
  686    searchable: bool,
  687    cursor_shape: CursorShape,
  688    current_line_highlight: Option<CurrentLineHighlight>,
  689    collapse_matches: bool,
  690    autoindent_mode: Option<AutoindentMode>,
  691    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  692    input_enabled: bool,
  693    use_modal_editing: bool,
  694    read_only: bool,
  695    leader_peer_id: Option<PeerId>,
  696    remote_id: Option<ViewId>,
  697    hover_state: HoverState,
  698    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  699    gutter_hovered: bool,
  700    hovered_link_state: Option<HoveredLinkState>,
  701    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  702    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  703    active_inline_completion: Option<InlineCompletionState>,
  704    /// Used to prevent flickering as the user types while the menu is open
  705    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  706    edit_prediction_settings: EditPredictionSettings,
  707    inline_completions_hidden_for_vim_mode: bool,
  708    show_inline_completions_override: Option<bool>,
  709    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  710    edit_prediction_preview: EditPredictionPreview,
  711    edit_prediction_indent_conflict: bool,
  712    edit_prediction_requires_modifier_in_indent_conflict: bool,
  713    inlay_hint_cache: InlayHintCache,
  714    inlay_hint_modifiers_toggled: bool,
  715    next_inlay_id: usize,
  716    _subscriptions: Vec<Subscription>,
  717    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  718    gutter_dimensions: GutterDimensions,
  719    style: Option<EditorStyle>,
  720    text_style_refinement: Option<TextStyleRefinement>,
  721    next_editor_action_id: EditorActionId,
  722    editor_actions:
  723        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  724    use_autoclose: bool,
  725    use_auto_surround: bool,
  726    auto_replace_emoji_shortcode: bool,
  727    show_git_blame_gutter: bool,
  728    show_git_blame_inline: bool,
  729    show_git_blame_inline_delay_task: Option<Task<()>>,
  730    git_blame_inline_tooltip: Option<WeakEntity<crate::commit_tooltip::CommitTooltip>>,
  731    git_blame_inline_enabled: bool,
  732    serialize_dirty_buffers: bool,
  733    show_selection_menu: Option<bool>,
  734    blame: Option<Entity<GitBlame>>,
  735    blame_subscription: Option<Subscription>,
  736    custom_context_menu: Option<
  737        Box<
  738            dyn 'static
  739                + Fn(
  740                    &mut Self,
  741                    DisplayPoint,
  742                    &mut Window,
  743                    &mut Context<Self>,
  744                ) -> Option<Entity<ui::ContextMenu>>,
  745        >,
  746    >,
  747    last_bounds: Option<Bounds<Pixels>>,
  748    last_position_map: Option<Rc<PositionMap>>,
  749    expect_bounds_change: Option<Bounds<Pixels>>,
  750    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
  751    tasks_update_task: Option<Task<()>>,
  752    in_project_search: bool,
  753    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
  754    breadcrumb_header: Option<String>,
  755    focused_block: Option<FocusedBlock>,
  756    next_scroll_position: NextScrollCursorCenterTopBottom,
  757    addons: HashMap<TypeId, Box<dyn Addon>>,
  758    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
  759    load_diff_task: Option<Shared<Task<()>>>,
  760    selection_mark_mode: bool,
  761    toggle_fold_multiple_buffers: Task<()>,
  762    _scroll_cursor_center_top_bottom_task: Task<()>,
  763    serialize_selections: Task<()>,
  764}
  765
  766#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
  767enum NextScrollCursorCenterTopBottom {
  768    #[default]
  769    Center,
  770    Top,
  771    Bottom,
  772}
  773
  774impl NextScrollCursorCenterTopBottom {
  775    fn next(&self) -> Self {
  776        match self {
  777            Self::Center => Self::Top,
  778            Self::Top => Self::Bottom,
  779            Self::Bottom => Self::Center,
  780        }
  781    }
  782}
  783
  784#[derive(Clone)]
  785pub struct EditorSnapshot {
  786    pub mode: EditorMode,
  787    show_gutter: bool,
  788    show_line_numbers: Option<bool>,
  789    show_git_diff_gutter: Option<bool>,
  790    show_code_actions: Option<bool>,
  791    show_runnables: Option<bool>,
  792    git_blame_gutter_max_author_length: Option<usize>,
  793    pub display_snapshot: DisplaySnapshot,
  794    pub placeholder_text: Option<Arc<str>>,
  795    is_focused: bool,
  796    scroll_anchor: ScrollAnchor,
  797    ongoing_scroll: OngoingScroll,
  798    current_line_highlight: CurrentLineHighlight,
  799    gutter_hovered: bool,
  800}
  801
  802const GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED: usize = 20;
  803
  804#[derive(Default, Debug, Clone, Copy)]
  805pub struct GutterDimensions {
  806    pub left_padding: Pixels,
  807    pub right_padding: Pixels,
  808    pub width: Pixels,
  809    pub margin: Pixels,
  810    pub git_blame_entries_width: Option<Pixels>,
  811}
  812
  813impl GutterDimensions {
  814    /// The full width of the space taken up by the gutter.
  815    pub fn full_width(&self) -> Pixels {
  816        self.margin + self.width
  817    }
  818
  819    /// The width of the space reserved for the fold indicators,
  820    /// use alongside 'justify_end' and `gutter_width` to
  821    /// right align content with the line numbers
  822    pub fn fold_area_width(&self) -> Pixels {
  823        self.margin + self.right_padding
  824    }
  825}
  826
  827#[derive(Debug)]
  828pub struct RemoteSelection {
  829    pub replica_id: ReplicaId,
  830    pub selection: Selection<Anchor>,
  831    pub cursor_shape: CursorShape,
  832    pub peer_id: PeerId,
  833    pub line_mode: bool,
  834    pub participant_index: Option<ParticipantIndex>,
  835    pub user_name: Option<SharedString>,
  836}
  837
  838#[derive(Clone, Debug)]
  839struct SelectionHistoryEntry {
  840    selections: Arc<[Selection<Anchor>]>,
  841    select_next_state: Option<SelectNextState>,
  842    select_prev_state: Option<SelectNextState>,
  843    add_selections_state: Option<AddSelectionsState>,
  844}
  845
  846enum SelectionHistoryMode {
  847    Normal,
  848    Undoing,
  849    Redoing,
  850}
  851
  852#[derive(Clone, PartialEq, Eq, Hash)]
  853struct HoveredCursor {
  854    replica_id: u16,
  855    selection_id: usize,
  856}
  857
  858impl Default for SelectionHistoryMode {
  859    fn default() -> Self {
  860        Self::Normal
  861    }
  862}
  863
  864#[derive(Default)]
  865struct SelectionHistory {
  866    #[allow(clippy::type_complexity)]
  867    selections_by_transaction:
  868        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
  869    mode: SelectionHistoryMode,
  870    undo_stack: VecDeque<SelectionHistoryEntry>,
  871    redo_stack: VecDeque<SelectionHistoryEntry>,
  872}
  873
  874impl SelectionHistory {
  875    fn insert_transaction(
  876        &mut self,
  877        transaction_id: TransactionId,
  878        selections: Arc<[Selection<Anchor>]>,
  879    ) {
  880        self.selections_by_transaction
  881            .insert(transaction_id, (selections, None));
  882    }
  883
  884    #[allow(clippy::type_complexity)]
  885    fn transaction(
  886        &self,
  887        transaction_id: TransactionId,
  888    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  889        self.selections_by_transaction.get(&transaction_id)
  890    }
  891
  892    #[allow(clippy::type_complexity)]
  893    fn transaction_mut(
  894        &mut self,
  895        transaction_id: TransactionId,
  896    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  897        self.selections_by_transaction.get_mut(&transaction_id)
  898    }
  899
  900    fn push(&mut self, entry: SelectionHistoryEntry) {
  901        if !entry.selections.is_empty() {
  902            match self.mode {
  903                SelectionHistoryMode::Normal => {
  904                    self.push_undo(entry);
  905                    self.redo_stack.clear();
  906                }
  907                SelectionHistoryMode::Undoing => self.push_redo(entry),
  908                SelectionHistoryMode::Redoing => self.push_undo(entry),
  909            }
  910        }
  911    }
  912
  913    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
  914        if self
  915            .undo_stack
  916            .back()
  917            .map_or(true, |e| e.selections != entry.selections)
  918        {
  919            self.undo_stack.push_back(entry);
  920            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  921                self.undo_stack.pop_front();
  922            }
  923        }
  924    }
  925
  926    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
  927        if self
  928            .redo_stack
  929            .back()
  930            .map_or(true, |e| e.selections != entry.selections)
  931        {
  932            self.redo_stack.push_back(entry);
  933            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  934                self.redo_stack.pop_front();
  935            }
  936        }
  937    }
  938}
  939
  940struct RowHighlight {
  941    index: usize,
  942    range: Range<Anchor>,
  943    color: Hsla,
  944    should_autoscroll: bool,
  945}
  946
  947#[derive(Clone, Debug)]
  948struct AddSelectionsState {
  949    above: bool,
  950    stack: Vec<usize>,
  951}
  952
  953#[derive(Clone)]
  954struct SelectNextState {
  955    query: AhoCorasick,
  956    wordwise: bool,
  957    done: bool,
  958}
  959
  960impl std::fmt::Debug for SelectNextState {
  961    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  962        f.debug_struct(std::any::type_name::<Self>())
  963            .field("wordwise", &self.wordwise)
  964            .field("done", &self.done)
  965            .finish()
  966    }
  967}
  968
  969#[derive(Debug)]
  970struct AutocloseRegion {
  971    selection_id: usize,
  972    range: Range<Anchor>,
  973    pair: BracketPair,
  974}
  975
  976#[derive(Debug)]
  977struct SnippetState {
  978    ranges: Vec<Vec<Range<Anchor>>>,
  979    active_index: usize,
  980    choices: Vec<Option<Vec<String>>>,
  981}
  982
  983#[doc(hidden)]
  984pub struct RenameState {
  985    pub range: Range<Anchor>,
  986    pub old_name: Arc<str>,
  987    pub editor: Entity<Editor>,
  988    block_id: CustomBlockId,
  989}
  990
  991struct InvalidationStack<T>(Vec<T>);
  992
  993struct RegisteredInlineCompletionProvider {
  994    provider: Arc<dyn InlineCompletionProviderHandle>,
  995    _subscription: Subscription,
  996}
  997
  998#[derive(Debug, PartialEq, Eq)]
  999struct ActiveDiagnosticGroup {
 1000    primary_range: Range<Anchor>,
 1001    primary_message: String,
 1002    group_id: usize,
 1003    blocks: HashMap<CustomBlockId, Diagnostic>,
 1004    is_valid: bool,
 1005}
 1006
 1007#[derive(Serialize, Deserialize, Clone, Debug)]
 1008pub struct ClipboardSelection {
 1009    /// The number of bytes in this selection.
 1010    pub len: usize,
 1011    /// Whether this was a full-line selection.
 1012    pub is_entire_line: bool,
 1013    /// The column where this selection originally started.
 1014    pub start_column: u32,
 1015}
 1016
 1017#[derive(Debug)]
 1018pub(crate) struct NavigationData {
 1019    cursor_anchor: Anchor,
 1020    cursor_position: Point,
 1021    scroll_anchor: ScrollAnchor,
 1022    scroll_top_row: u32,
 1023}
 1024
 1025#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1026pub enum GotoDefinitionKind {
 1027    Symbol,
 1028    Declaration,
 1029    Type,
 1030    Implementation,
 1031}
 1032
 1033#[derive(Debug, Clone)]
 1034enum InlayHintRefreshReason {
 1035    Toggle(bool),
 1036    SettingsChange(InlayHintSettings),
 1037    NewLinesShown,
 1038    BufferEdited(HashSet<Arc<Language>>),
 1039    RefreshRequested,
 1040    ExcerptsRemoved(Vec<ExcerptId>),
 1041}
 1042
 1043impl InlayHintRefreshReason {
 1044    fn description(&self) -> &'static str {
 1045        match self {
 1046            Self::Toggle(_) => "toggle",
 1047            Self::SettingsChange(_) => "settings change",
 1048            Self::NewLinesShown => "new lines shown",
 1049            Self::BufferEdited(_) => "buffer edited",
 1050            Self::RefreshRequested => "refresh requested",
 1051            Self::ExcerptsRemoved(_) => "excerpts removed",
 1052        }
 1053    }
 1054}
 1055
 1056pub enum FormatTarget {
 1057    Buffers,
 1058    Ranges(Vec<Range<MultiBufferPoint>>),
 1059}
 1060
 1061pub(crate) struct FocusedBlock {
 1062    id: BlockId,
 1063    focus_handle: WeakFocusHandle,
 1064}
 1065
 1066#[derive(Clone)]
 1067enum JumpData {
 1068    MultiBufferRow {
 1069        row: MultiBufferRow,
 1070        line_offset_from_top: u32,
 1071    },
 1072    MultiBufferPoint {
 1073        excerpt_id: ExcerptId,
 1074        position: Point,
 1075        anchor: text::Anchor,
 1076        line_offset_from_top: u32,
 1077    },
 1078}
 1079
 1080pub enum MultibufferSelectionMode {
 1081    First,
 1082    All,
 1083}
 1084
 1085impl Editor {
 1086    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1087        let buffer = cx.new(|cx| Buffer::local("", cx));
 1088        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1089        Self::new(
 1090            EditorMode::SingleLine { auto_width: false },
 1091            buffer,
 1092            None,
 1093            false,
 1094            window,
 1095            cx,
 1096        )
 1097    }
 1098
 1099    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1100        let buffer = cx.new(|cx| Buffer::local("", cx));
 1101        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1102        Self::new(EditorMode::Full, buffer, None, false, window, cx)
 1103    }
 1104
 1105    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1106        let buffer = cx.new(|cx| Buffer::local("", cx));
 1107        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1108        Self::new(
 1109            EditorMode::SingleLine { auto_width: true },
 1110            buffer,
 1111            None,
 1112            false,
 1113            window,
 1114            cx,
 1115        )
 1116    }
 1117
 1118    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1119        let buffer = cx.new(|cx| Buffer::local("", cx));
 1120        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1121        Self::new(
 1122            EditorMode::AutoHeight { max_lines },
 1123            buffer,
 1124            None,
 1125            false,
 1126            window,
 1127            cx,
 1128        )
 1129    }
 1130
 1131    pub fn for_buffer(
 1132        buffer: Entity<Buffer>,
 1133        project: Option<Entity<Project>>,
 1134        window: &mut Window,
 1135        cx: &mut Context<Self>,
 1136    ) -> Self {
 1137        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1138        Self::new(EditorMode::Full, buffer, project, false, window, cx)
 1139    }
 1140
 1141    pub fn for_multibuffer(
 1142        buffer: Entity<MultiBuffer>,
 1143        project: Option<Entity<Project>>,
 1144        show_excerpt_controls: bool,
 1145        window: &mut Window,
 1146        cx: &mut Context<Self>,
 1147    ) -> Self {
 1148        Self::new(
 1149            EditorMode::Full,
 1150            buffer,
 1151            project,
 1152            show_excerpt_controls,
 1153            window,
 1154            cx,
 1155        )
 1156    }
 1157
 1158    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1159        let show_excerpt_controls = self.display_map.read(cx).show_excerpt_controls();
 1160        let mut clone = Self::new(
 1161            self.mode,
 1162            self.buffer.clone(),
 1163            self.project.clone(),
 1164            show_excerpt_controls,
 1165            window,
 1166            cx,
 1167        );
 1168        self.display_map.update(cx, |display_map, cx| {
 1169            let snapshot = display_map.snapshot(cx);
 1170            clone.display_map.update(cx, |display_map, cx| {
 1171                display_map.set_state(&snapshot, cx);
 1172            });
 1173        });
 1174        clone.selections.clone_state(&self.selections);
 1175        clone.scroll_manager.clone_state(&self.scroll_manager);
 1176        clone.searchable = self.searchable;
 1177        clone
 1178    }
 1179
 1180    pub fn new(
 1181        mode: EditorMode,
 1182        buffer: Entity<MultiBuffer>,
 1183        project: Option<Entity<Project>>,
 1184        show_excerpt_controls: bool,
 1185        window: &mut Window,
 1186        cx: &mut Context<Self>,
 1187    ) -> Self {
 1188        let style = window.text_style();
 1189        let font_size = style.font_size.to_pixels(window.rem_size());
 1190        let editor = cx.entity().downgrade();
 1191        let fold_placeholder = FoldPlaceholder {
 1192            constrain_width: true,
 1193            render: Arc::new(move |fold_id, fold_range, cx| {
 1194                let editor = editor.clone();
 1195                div()
 1196                    .id(fold_id)
 1197                    .bg(cx.theme().colors().ghost_element_background)
 1198                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1199                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1200                    .rounded_sm()
 1201                    .size_full()
 1202                    .cursor_pointer()
 1203                    .child("")
 1204                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1205                    .on_click(move |_, _window, cx| {
 1206                        editor
 1207                            .update(cx, |editor, cx| {
 1208                                editor.unfold_ranges(
 1209                                    &[fold_range.start..fold_range.end],
 1210                                    true,
 1211                                    false,
 1212                                    cx,
 1213                                );
 1214                                cx.stop_propagation();
 1215                            })
 1216                            .ok();
 1217                    })
 1218                    .into_any()
 1219            }),
 1220            merge_adjacent: true,
 1221            ..Default::default()
 1222        };
 1223        let display_map = cx.new(|cx| {
 1224            DisplayMap::new(
 1225                buffer.clone(),
 1226                style.font(),
 1227                font_size,
 1228                None,
 1229                show_excerpt_controls,
 1230                FILE_HEADER_HEIGHT,
 1231                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1232                MULTI_BUFFER_EXCERPT_FOOTER_HEIGHT,
 1233                fold_placeholder,
 1234                cx,
 1235            )
 1236        });
 1237
 1238        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1239
 1240        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1241
 1242        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1243            .then(|| language_settings::SoftWrap::None);
 1244
 1245        let mut project_subscriptions = Vec::new();
 1246        if mode == EditorMode::Full {
 1247            if let Some(project) = project.as_ref() {
 1248                if buffer.read(cx).is_singleton() {
 1249                    project_subscriptions.push(cx.observe_in(project, window, |_, _, _, cx| {
 1250                        cx.emit(EditorEvent::TitleChanged);
 1251                    }));
 1252                }
 1253                project_subscriptions.push(cx.subscribe_in(
 1254                    project,
 1255                    window,
 1256                    |editor, _, event, window, cx| {
 1257                        if let project::Event::RefreshInlayHints = event {
 1258                            editor
 1259                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1260                        } else if let project::Event::SnippetEdit(id, snippet_edits) = event {
 1261                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1262                                let focus_handle = editor.focus_handle(cx);
 1263                                if focus_handle.is_focused(window) {
 1264                                    let snapshot = buffer.read(cx).snapshot();
 1265                                    for (range, snippet) in snippet_edits {
 1266                                        let editor_range =
 1267                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1268                                        editor
 1269                                            .insert_snippet(
 1270                                                &[editor_range],
 1271                                                snippet.clone(),
 1272                                                window,
 1273                                                cx,
 1274                                            )
 1275                                            .ok();
 1276                                    }
 1277                                }
 1278                            }
 1279                        }
 1280                    },
 1281                ));
 1282                if let Some(task_inventory) = project
 1283                    .read(cx)
 1284                    .task_store()
 1285                    .read(cx)
 1286                    .task_inventory()
 1287                    .cloned()
 1288                {
 1289                    project_subscriptions.push(cx.observe_in(
 1290                        &task_inventory,
 1291                        window,
 1292                        |editor, _, window, cx| {
 1293                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1294                        },
 1295                    ));
 1296                }
 1297            }
 1298        }
 1299
 1300        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1301
 1302        let inlay_hint_settings =
 1303            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1304        let focus_handle = cx.focus_handle();
 1305        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1306            .detach();
 1307        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1308            .detach();
 1309        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1310            .detach();
 1311        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1312            .detach();
 1313
 1314        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1315            Some(false)
 1316        } else {
 1317            None
 1318        };
 1319
 1320        let mut code_action_providers = Vec::new();
 1321        let mut load_uncommitted_diff = None;
 1322        if let Some(project) = project.clone() {
 1323            load_uncommitted_diff = Some(
 1324                get_uncommitted_diff_for_buffer(
 1325                    &project,
 1326                    buffer.read(cx).all_buffers(),
 1327                    buffer.clone(),
 1328                    cx,
 1329                )
 1330                .shared(),
 1331            );
 1332            code_action_providers.push(Rc::new(project) as Rc<_>);
 1333        }
 1334
 1335        let mut this = Self {
 1336            focus_handle,
 1337            show_cursor_when_unfocused: false,
 1338            last_focused_descendant: None,
 1339            buffer: buffer.clone(),
 1340            display_map: display_map.clone(),
 1341            selections,
 1342            scroll_manager: ScrollManager::new(cx),
 1343            columnar_selection_tail: None,
 1344            add_selections_state: None,
 1345            select_next_state: None,
 1346            select_prev_state: None,
 1347            selection_history: Default::default(),
 1348            autoclose_regions: Default::default(),
 1349            snippet_stack: Default::default(),
 1350            select_larger_syntax_node_stack: Vec::new(),
 1351            ime_transaction: Default::default(),
 1352            active_diagnostics: None,
 1353            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1354            inline_diagnostics_update: Task::ready(()),
 1355            inline_diagnostics: Vec::new(),
 1356            soft_wrap_mode_override,
 1357            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1358            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1359            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1360            project,
 1361            blink_manager: blink_manager.clone(),
 1362            show_local_selections: true,
 1363            show_scrollbars: true,
 1364            mode,
 1365            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1366            show_gutter: mode == EditorMode::Full,
 1367            show_line_numbers: None,
 1368            use_relative_line_numbers: None,
 1369            show_git_diff_gutter: None,
 1370            show_code_actions: None,
 1371            show_runnables: None,
 1372            show_wrap_guides: None,
 1373            show_indent_guides,
 1374            placeholder_text: None,
 1375            highlight_order: 0,
 1376            highlighted_rows: HashMap::default(),
 1377            background_highlights: Default::default(),
 1378            gutter_highlights: TreeMap::default(),
 1379            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1380            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1381            nav_history: None,
 1382            context_menu: RefCell::new(None),
 1383            mouse_context_menu: None,
 1384            completion_tasks: Default::default(),
 1385            signature_help_state: SignatureHelpState::default(),
 1386            auto_signature_help: None,
 1387            find_all_references_task_sources: Vec::new(),
 1388            next_completion_id: 0,
 1389            next_inlay_id: 0,
 1390            code_action_providers,
 1391            available_code_actions: Default::default(),
 1392            code_actions_task: Default::default(),
 1393            selection_highlight_task: Default::default(),
 1394            document_highlights_task: Default::default(),
 1395            linked_editing_range_task: Default::default(),
 1396            pending_rename: Default::default(),
 1397            searchable: true,
 1398            cursor_shape: EditorSettings::get_global(cx)
 1399                .cursor_shape
 1400                .unwrap_or_default(),
 1401            current_line_highlight: None,
 1402            autoindent_mode: Some(AutoindentMode::EachLine),
 1403            collapse_matches: false,
 1404            workspace: None,
 1405            input_enabled: true,
 1406            use_modal_editing: mode == EditorMode::Full,
 1407            read_only: false,
 1408            use_autoclose: true,
 1409            use_auto_surround: true,
 1410            auto_replace_emoji_shortcode: false,
 1411            leader_peer_id: None,
 1412            remote_id: None,
 1413            hover_state: Default::default(),
 1414            pending_mouse_down: None,
 1415            hovered_link_state: Default::default(),
 1416            edit_prediction_provider: None,
 1417            active_inline_completion: None,
 1418            stale_inline_completion_in_menu: None,
 1419            edit_prediction_preview: EditPredictionPreview::Inactive {
 1420                released_too_fast: false,
 1421            },
 1422            inline_diagnostics_enabled: mode == EditorMode::Full,
 1423            inlay_hint_modifiers_toggled: false,
 1424            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1425
 1426            gutter_hovered: false,
 1427            pixel_position_of_newest_cursor: None,
 1428            last_bounds: None,
 1429            last_position_map: None,
 1430            expect_bounds_change: None,
 1431            gutter_dimensions: GutterDimensions::default(),
 1432            style: None,
 1433            show_cursor_names: false,
 1434            hovered_cursors: Default::default(),
 1435            next_editor_action_id: EditorActionId::default(),
 1436            editor_actions: Rc::default(),
 1437            inline_completions_hidden_for_vim_mode: false,
 1438            show_inline_completions_override: None,
 1439            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1440            edit_prediction_settings: EditPredictionSettings::Disabled,
 1441            edit_prediction_indent_conflict: false,
 1442            edit_prediction_requires_modifier_in_indent_conflict: true,
 1443            custom_context_menu: None,
 1444            show_git_blame_gutter: false,
 1445            show_git_blame_inline: false,
 1446            show_selection_menu: None,
 1447            show_git_blame_inline_delay_task: None,
 1448            git_blame_inline_tooltip: None,
 1449            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1450            serialize_dirty_buffers: ProjectSettings::get_global(cx)
 1451                .session
 1452                .restore_unsaved_buffers,
 1453            blame: None,
 1454            blame_subscription: None,
 1455            tasks: Default::default(),
 1456            _subscriptions: vec![
 1457                cx.observe(&buffer, Self::on_buffer_changed),
 1458                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1459                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1460                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1461                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1462                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1463                cx.observe_window_activation(window, |editor, window, cx| {
 1464                    let active = window.is_window_active();
 1465                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1466                        if active {
 1467                            blink_manager.enable(cx);
 1468                        } else {
 1469                            blink_manager.disable(cx);
 1470                        }
 1471                    });
 1472                }),
 1473            ],
 1474            tasks_update_task: None,
 1475            linked_edit_ranges: Default::default(),
 1476            in_project_search: false,
 1477            previous_search_ranges: None,
 1478            breadcrumb_header: None,
 1479            focused_block: None,
 1480            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1481            addons: HashMap::default(),
 1482            registered_buffers: HashMap::default(),
 1483            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1484            selection_mark_mode: false,
 1485            toggle_fold_multiple_buffers: Task::ready(()),
 1486            serialize_selections: Task::ready(()),
 1487            text_style_refinement: None,
 1488            load_diff_task: load_uncommitted_diff,
 1489        };
 1490        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1491        this._subscriptions.extend(project_subscriptions);
 1492
 1493        this.end_selection(window, cx);
 1494        this.scroll_manager.show_scrollbar(window, cx);
 1495
 1496        if mode == EditorMode::Full {
 1497            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1498            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1499
 1500            if this.git_blame_inline_enabled {
 1501                this.git_blame_inline_enabled = true;
 1502                this.start_git_blame_inline(false, window, cx);
 1503            }
 1504
 1505            if let Some(buffer) = buffer.read(cx).as_singleton() {
 1506                if let Some(project) = this.project.as_ref() {
 1507                    let handle = project.update(cx, |project, cx| {
 1508                        project.register_buffer_with_language_servers(&buffer, cx)
 1509                    });
 1510                    this.registered_buffers
 1511                        .insert(buffer.read(cx).remote_id(), handle);
 1512                }
 1513            }
 1514        }
 1515
 1516        this.report_editor_event("Editor Opened", None, cx);
 1517        this
 1518    }
 1519
 1520    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 1521        self.mouse_context_menu
 1522            .as_ref()
 1523            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 1524    }
 1525
 1526    fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 1527        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 1528    }
 1529
 1530    fn key_context_internal(
 1531        &self,
 1532        has_active_edit_prediction: bool,
 1533        window: &Window,
 1534        cx: &App,
 1535    ) -> KeyContext {
 1536        let mut key_context = KeyContext::new_with_defaults();
 1537        key_context.add("Editor");
 1538        let mode = match self.mode {
 1539            EditorMode::SingleLine { .. } => "single_line",
 1540            EditorMode::AutoHeight { .. } => "auto_height",
 1541            EditorMode::Full => "full",
 1542        };
 1543
 1544        if EditorSettings::jupyter_enabled(cx) {
 1545            key_context.add("jupyter");
 1546        }
 1547
 1548        key_context.set("mode", mode);
 1549        if self.pending_rename.is_some() {
 1550            key_context.add("renaming");
 1551        }
 1552
 1553        match self.context_menu.borrow().as_ref() {
 1554            Some(CodeContextMenu::Completions(_)) => {
 1555                key_context.add("menu");
 1556                key_context.add("showing_completions");
 1557            }
 1558            Some(CodeContextMenu::CodeActions(_)) => {
 1559                key_context.add("menu");
 1560                key_context.add("showing_code_actions")
 1561            }
 1562            None => {}
 1563        }
 1564
 1565        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 1566        if !self.focus_handle(cx).contains_focused(window, cx)
 1567            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 1568        {
 1569            for addon in self.addons.values() {
 1570                addon.extend_key_context(&mut key_context, cx)
 1571            }
 1572        }
 1573
 1574        if let Some(extension) = self
 1575            .buffer
 1576            .read(cx)
 1577            .as_singleton()
 1578            .and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str())
 1579        {
 1580            key_context.set("extension", extension.to_string());
 1581        }
 1582
 1583        if has_active_edit_prediction {
 1584            if self.edit_prediction_in_conflict() {
 1585                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 1586            } else {
 1587                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 1588                key_context.add("copilot_suggestion");
 1589            }
 1590        }
 1591
 1592        if self.selection_mark_mode {
 1593            key_context.add("selection_mode");
 1594        }
 1595
 1596        key_context
 1597    }
 1598
 1599    pub fn edit_prediction_in_conflict(&self) -> bool {
 1600        if !self.show_edit_predictions_in_menu() {
 1601            return false;
 1602        }
 1603
 1604        let showing_completions = self
 1605            .context_menu
 1606            .borrow()
 1607            .as_ref()
 1608            .map_or(false, |context| {
 1609                matches!(context, CodeContextMenu::Completions(_))
 1610            });
 1611
 1612        showing_completions
 1613            || self.edit_prediction_requires_modifier()
 1614            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 1615            // bindings to insert tab characters.
 1616            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 1617    }
 1618
 1619    pub fn accept_edit_prediction_keybind(
 1620        &self,
 1621        window: &Window,
 1622        cx: &App,
 1623    ) -> AcceptEditPredictionBinding {
 1624        let key_context = self.key_context_internal(true, window, cx);
 1625        let in_conflict = self.edit_prediction_in_conflict();
 1626
 1627        AcceptEditPredictionBinding(
 1628            window
 1629                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 1630                .into_iter()
 1631                .filter(|binding| {
 1632                    !in_conflict
 1633                        || binding
 1634                            .keystrokes()
 1635                            .first()
 1636                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 1637                })
 1638                .rev()
 1639                .min_by_key(|binding| {
 1640                    binding
 1641                        .keystrokes()
 1642                        .first()
 1643                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 1644                }),
 1645        )
 1646    }
 1647
 1648    pub fn new_file(
 1649        workspace: &mut Workspace,
 1650        _: &workspace::NewFile,
 1651        window: &mut Window,
 1652        cx: &mut Context<Workspace>,
 1653    ) {
 1654        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 1655            "Failed to create buffer",
 1656            window,
 1657            cx,
 1658            |e, _, _| match e.error_code() {
 1659                ErrorCode::RemoteUpgradeRequired => Some(format!(
 1660                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 1661                e.error_tag("required").unwrap_or("the latest version")
 1662            )),
 1663                _ => None,
 1664            },
 1665        );
 1666    }
 1667
 1668    pub fn new_in_workspace(
 1669        workspace: &mut Workspace,
 1670        window: &mut Window,
 1671        cx: &mut Context<Workspace>,
 1672    ) -> Task<Result<Entity<Editor>>> {
 1673        let project = workspace.project().clone();
 1674        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 1675
 1676        cx.spawn_in(window, |workspace, mut cx| async move {
 1677            let buffer = create.await?;
 1678            workspace.update_in(&mut cx, |workspace, window, cx| {
 1679                let editor =
 1680                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 1681                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 1682                editor
 1683            })
 1684        })
 1685    }
 1686
 1687    fn new_file_vertical(
 1688        workspace: &mut Workspace,
 1689        _: &workspace::NewFileSplitVertical,
 1690        window: &mut Window,
 1691        cx: &mut Context<Workspace>,
 1692    ) {
 1693        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 1694    }
 1695
 1696    fn new_file_horizontal(
 1697        workspace: &mut Workspace,
 1698        _: &workspace::NewFileSplitHorizontal,
 1699        window: &mut Window,
 1700        cx: &mut Context<Workspace>,
 1701    ) {
 1702        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 1703    }
 1704
 1705    fn new_file_in_direction(
 1706        workspace: &mut Workspace,
 1707        direction: SplitDirection,
 1708        window: &mut Window,
 1709        cx: &mut Context<Workspace>,
 1710    ) {
 1711        let project = workspace.project().clone();
 1712        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 1713
 1714        cx.spawn_in(window, |workspace, mut cx| async move {
 1715            let buffer = create.await?;
 1716            workspace.update_in(&mut cx, move |workspace, window, cx| {
 1717                workspace.split_item(
 1718                    direction,
 1719                    Box::new(
 1720                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 1721                    ),
 1722                    window,
 1723                    cx,
 1724                )
 1725            })?;
 1726            anyhow::Ok(())
 1727        })
 1728        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 1729            match e.error_code() {
 1730                ErrorCode::RemoteUpgradeRequired => Some(format!(
 1731                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 1732                e.error_tag("required").unwrap_or("the latest version")
 1733            )),
 1734                _ => None,
 1735            }
 1736        });
 1737    }
 1738
 1739    pub fn leader_peer_id(&self) -> Option<PeerId> {
 1740        self.leader_peer_id
 1741    }
 1742
 1743    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 1744        &self.buffer
 1745    }
 1746
 1747    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 1748        self.workspace.as_ref()?.0.upgrade()
 1749    }
 1750
 1751    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 1752        self.buffer().read(cx).title(cx)
 1753    }
 1754
 1755    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 1756        let git_blame_gutter_max_author_length = self
 1757            .render_git_blame_gutter(cx)
 1758            .then(|| {
 1759                if let Some(blame) = self.blame.as_ref() {
 1760                    let max_author_length =
 1761                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 1762                    Some(max_author_length)
 1763                } else {
 1764                    None
 1765                }
 1766            })
 1767            .flatten();
 1768
 1769        EditorSnapshot {
 1770            mode: self.mode,
 1771            show_gutter: self.show_gutter,
 1772            show_line_numbers: self.show_line_numbers,
 1773            show_git_diff_gutter: self.show_git_diff_gutter,
 1774            show_code_actions: self.show_code_actions,
 1775            show_runnables: self.show_runnables,
 1776            git_blame_gutter_max_author_length,
 1777            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 1778            scroll_anchor: self.scroll_manager.anchor(),
 1779            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 1780            placeholder_text: self.placeholder_text.clone(),
 1781            is_focused: self.focus_handle.is_focused(window),
 1782            current_line_highlight: self
 1783                .current_line_highlight
 1784                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 1785            gutter_hovered: self.gutter_hovered,
 1786        }
 1787    }
 1788
 1789    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 1790        self.buffer.read(cx).language_at(point, cx)
 1791    }
 1792
 1793    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 1794        self.buffer.read(cx).read(cx).file_at(point).cloned()
 1795    }
 1796
 1797    pub fn active_excerpt(
 1798        &self,
 1799        cx: &App,
 1800    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 1801        self.buffer
 1802            .read(cx)
 1803            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 1804    }
 1805
 1806    pub fn mode(&self) -> EditorMode {
 1807        self.mode
 1808    }
 1809
 1810    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 1811        self.collaboration_hub.as_deref()
 1812    }
 1813
 1814    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 1815        self.collaboration_hub = Some(hub);
 1816    }
 1817
 1818    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 1819        self.in_project_search = in_project_search;
 1820    }
 1821
 1822    pub fn set_custom_context_menu(
 1823        &mut self,
 1824        f: impl 'static
 1825            + Fn(
 1826                &mut Self,
 1827                DisplayPoint,
 1828                &mut Window,
 1829                &mut Context<Self>,
 1830            ) -> Option<Entity<ui::ContextMenu>>,
 1831    ) {
 1832        self.custom_context_menu = Some(Box::new(f))
 1833    }
 1834
 1835    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 1836        self.completion_provider = provider;
 1837    }
 1838
 1839    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 1840        self.semantics_provider.clone()
 1841    }
 1842
 1843    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 1844        self.semantics_provider = provider;
 1845    }
 1846
 1847    pub fn set_edit_prediction_provider<T>(
 1848        &mut self,
 1849        provider: Option<Entity<T>>,
 1850        window: &mut Window,
 1851        cx: &mut Context<Self>,
 1852    ) where
 1853        T: EditPredictionProvider,
 1854    {
 1855        self.edit_prediction_provider =
 1856            provider.map(|provider| RegisteredInlineCompletionProvider {
 1857                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 1858                    if this.focus_handle.is_focused(window) {
 1859                        this.update_visible_inline_completion(window, cx);
 1860                    }
 1861                }),
 1862                provider: Arc::new(provider),
 1863            });
 1864        self.update_edit_prediction_settings(cx);
 1865        self.refresh_inline_completion(false, false, window, cx);
 1866    }
 1867
 1868    pub fn placeholder_text(&self) -> Option<&str> {
 1869        self.placeholder_text.as_deref()
 1870    }
 1871
 1872    pub fn set_placeholder_text(
 1873        &mut self,
 1874        placeholder_text: impl Into<Arc<str>>,
 1875        cx: &mut Context<Self>,
 1876    ) {
 1877        let placeholder_text = Some(placeholder_text.into());
 1878        if self.placeholder_text != placeholder_text {
 1879            self.placeholder_text = placeholder_text;
 1880            cx.notify();
 1881        }
 1882    }
 1883
 1884    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 1885        self.cursor_shape = cursor_shape;
 1886
 1887        // Disrupt blink for immediate user feedback that the cursor shape has changed
 1888        self.blink_manager.update(cx, BlinkManager::show_cursor);
 1889
 1890        cx.notify();
 1891    }
 1892
 1893    pub fn set_current_line_highlight(
 1894        &mut self,
 1895        current_line_highlight: Option<CurrentLineHighlight>,
 1896    ) {
 1897        self.current_line_highlight = current_line_highlight;
 1898    }
 1899
 1900    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 1901        self.collapse_matches = collapse_matches;
 1902    }
 1903
 1904    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 1905        let buffers = self.buffer.read(cx).all_buffers();
 1906        let Some(project) = self.project.as_ref() else {
 1907            return;
 1908        };
 1909        project.update(cx, |project, cx| {
 1910            for buffer in buffers {
 1911                self.registered_buffers
 1912                    .entry(buffer.read(cx).remote_id())
 1913                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 1914            }
 1915        })
 1916    }
 1917
 1918    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 1919        if self.collapse_matches {
 1920            return range.start..range.start;
 1921        }
 1922        range.clone()
 1923    }
 1924
 1925    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 1926        if self.display_map.read(cx).clip_at_line_ends != clip {
 1927            self.display_map
 1928                .update(cx, |map, _| map.clip_at_line_ends = clip);
 1929        }
 1930    }
 1931
 1932    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 1933        self.input_enabled = input_enabled;
 1934    }
 1935
 1936    pub fn set_inline_completions_hidden_for_vim_mode(
 1937        &mut self,
 1938        hidden: bool,
 1939        window: &mut Window,
 1940        cx: &mut Context<Self>,
 1941    ) {
 1942        if hidden != self.inline_completions_hidden_for_vim_mode {
 1943            self.inline_completions_hidden_for_vim_mode = hidden;
 1944            if hidden {
 1945                self.update_visible_inline_completion(window, cx);
 1946            } else {
 1947                self.refresh_inline_completion(true, false, window, cx);
 1948            }
 1949        }
 1950    }
 1951
 1952    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 1953        self.menu_inline_completions_policy = value;
 1954    }
 1955
 1956    pub fn set_autoindent(&mut self, autoindent: bool) {
 1957        if autoindent {
 1958            self.autoindent_mode = Some(AutoindentMode::EachLine);
 1959        } else {
 1960            self.autoindent_mode = None;
 1961        }
 1962    }
 1963
 1964    pub fn read_only(&self, cx: &App) -> bool {
 1965        self.read_only || self.buffer.read(cx).read_only()
 1966    }
 1967
 1968    pub fn set_read_only(&mut self, read_only: bool) {
 1969        self.read_only = read_only;
 1970    }
 1971
 1972    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 1973        self.use_autoclose = autoclose;
 1974    }
 1975
 1976    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 1977        self.use_auto_surround = auto_surround;
 1978    }
 1979
 1980    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 1981        self.auto_replace_emoji_shortcode = auto_replace;
 1982    }
 1983
 1984    pub fn toggle_edit_predictions(
 1985        &mut self,
 1986        _: &ToggleEditPrediction,
 1987        window: &mut Window,
 1988        cx: &mut Context<Self>,
 1989    ) {
 1990        if self.show_inline_completions_override.is_some() {
 1991            self.set_show_edit_predictions(None, window, cx);
 1992        } else {
 1993            let show_edit_predictions = !self.edit_predictions_enabled();
 1994            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 1995        }
 1996    }
 1997
 1998    pub fn set_show_edit_predictions(
 1999        &mut self,
 2000        show_edit_predictions: Option<bool>,
 2001        window: &mut Window,
 2002        cx: &mut Context<Self>,
 2003    ) {
 2004        self.show_inline_completions_override = show_edit_predictions;
 2005        self.update_edit_prediction_settings(cx);
 2006
 2007        if let Some(false) = show_edit_predictions {
 2008            self.discard_inline_completion(false, cx);
 2009        } else {
 2010            self.refresh_inline_completion(false, true, window, cx);
 2011        }
 2012    }
 2013
 2014    fn inline_completions_disabled_in_scope(
 2015        &self,
 2016        buffer: &Entity<Buffer>,
 2017        buffer_position: language::Anchor,
 2018        cx: &App,
 2019    ) -> bool {
 2020        let snapshot = buffer.read(cx).snapshot();
 2021        let settings = snapshot.settings_at(buffer_position, cx);
 2022
 2023        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2024            return false;
 2025        };
 2026
 2027        scope.override_name().map_or(false, |scope_name| {
 2028            settings
 2029                .edit_predictions_disabled_in
 2030                .iter()
 2031                .any(|s| s == scope_name)
 2032        })
 2033    }
 2034
 2035    pub fn set_use_modal_editing(&mut self, to: bool) {
 2036        self.use_modal_editing = to;
 2037    }
 2038
 2039    pub fn use_modal_editing(&self) -> bool {
 2040        self.use_modal_editing
 2041    }
 2042
 2043    fn selections_did_change(
 2044        &mut self,
 2045        local: bool,
 2046        old_cursor_position: &Anchor,
 2047        show_completions: bool,
 2048        window: &mut Window,
 2049        cx: &mut Context<Self>,
 2050    ) {
 2051        window.invalidate_character_coordinates();
 2052
 2053        // Copy selections to primary selection buffer
 2054        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2055        if local {
 2056            let selections = self.selections.all::<usize>(cx);
 2057            let buffer_handle = self.buffer.read(cx).read(cx);
 2058
 2059            let mut text = String::new();
 2060            for (index, selection) in selections.iter().enumerate() {
 2061                let text_for_selection = buffer_handle
 2062                    .text_for_range(selection.start..selection.end)
 2063                    .collect::<String>();
 2064
 2065                text.push_str(&text_for_selection);
 2066                if index != selections.len() - 1 {
 2067                    text.push('\n');
 2068                }
 2069            }
 2070
 2071            if !text.is_empty() {
 2072                cx.write_to_primary(ClipboardItem::new_string(text));
 2073            }
 2074        }
 2075
 2076        if self.focus_handle.is_focused(window) && self.leader_peer_id.is_none() {
 2077            self.buffer.update(cx, |buffer, cx| {
 2078                buffer.set_active_selections(
 2079                    &self.selections.disjoint_anchors(),
 2080                    self.selections.line_mode,
 2081                    self.cursor_shape,
 2082                    cx,
 2083                )
 2084            });
 2085        }
 2086        let display_map = self
 2087            .display_map
 2088            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2089        let buffer = &display_map.buffer_snapshot;
 2090        self.add_selections_state = None;
 2091        self.select_next_state = None;
 2092        self.select_prev_state = None;
 2093        self.select_larger_syntax_node_stack.clear();
 2094        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2095        self.snippet_stack
 2096            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2097        self.take_rename(false, window, cx);
 2098
 2099        let new_cursor_position = self.selections.newest_anchor().head();
 2100
 2101        self.push_to_nav_history(
 2102            *old_cursor_position,
 2103            Some(new_cursor_position.to_point(buffer)),
 2104            cx,
 2105        );
 2106
 2107        if local {
 2108            let new_cursor_position = self.selections.newest_anchor().head();
 2109            let mut context_menu = self.context_menu.borrow_mut();
 2110            let completion_menu = match context_menu.as_ref() {
 2111                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2112                _ => {
 2113                    *context_menu = None;
 2114                    None
 2115                }
 2116            };
 2117            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2118                if !self.registered_buffers.contains_key(&buffer_id) {
 2119                    if let Some(project) = self.project.as_ref() {
 2120                        project.update(cx, |project, cx| {
 2121                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2122                                return;
 2123                            };
 2124                            self.registered_buffers.insert(
 2125                                buffer_id,
 2126                                project.register_buffer_with_language_servers(&buffer, cx),
 2127                            );
 2128                        })
 2129                    }
 2130                }
 2131            }
 2132
 2133            if let Some(completion_menu) = completion_menu {
 2134                let cursor_position = new_cursor_position.to_offset(buffer);
 2135                let (word_range, kind) =
 2136                    buffer.surrounding_word(completion_menu.initial_position, true);
 2137                if kind == Some(CharKind::Word)
 2138                    && word_range.to_inclusive().contains(&cursor_position)
 2139                {
 2140                    let mut completion_menu = completion_menu.clone();
 2141                    drop(context_menu);
 2142
 2143                    let query = Self::completion_query(buffer, cursor_position);
 2144                    cx.spawn(move |this, mut cx| async move {
 2145                        completion_menu
 2146                            .filter(query.as_deref(), cx.background_executor().clone())
 2147                            .await;
 2148
 2149                        this.update(&mut cx, |this, cx| {
 2150                            let mut context_menu = this.context_menu.borrow_mut();
 2151                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2152                            else {
 2153                                return;
 2154                            };
 2155
 2156                            if menu.id > completion_menu.id {
 2157                                return;
 2158                            }
 2159
 2160                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2161                            drop(context_menu);
 2162                            cx.notify();
 2163                        })
 2164                    })
 2165                    .detach();
 2166
 2167                    if show_completions {
 2168                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2169                    }
 2170                } else {
 2171                    drop(context_menu);
 2172                    self.hide_context_menu(window, cx);
 2173                }
 2174            } else {
 2175                drop(context_menu);
 2176            }
 2177
 2178            hide_hover(self, cx);
 2179
 2180            if old_cursor_position.to_display_point(&display_map).row()
 2181                != new_cursor_position.to_display_point(&display_map).row()
 2182            {
 2183                self.available_code_actions.take();
 2184            }
 2185            self.refresh_code_actions(window, cx);
 2186            self.refresh_document_highlights(cx);
 2187            self.refresh_selected_text_highlights(window, cx);
 2188            refresh_matching_bracket_highlights(self, window, cx);
 2189            self.update_visible_inline_completion(window, cx);
 2190            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2191            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2192            if self.git_blame_inline_enabled {
 2193                self.start_inline_blame_timer(window, cx);
 2194            }
 2195        }
 2196
 2197        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2198        cx.emit(EditorEvent::SelectionsChanged { local });
 2199
 2200        let selections = &self.selections.disjoint;
 2201        if selections.len() == 1 {
 2202            cx.emit(SearchEvent::ActiveMatchChanged)
 2203        }
 2204        if local
 2205            && self.is_singleton(cx)
 2206            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 2207        {
 2208            if let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) {
 2209                let background_executor = cx.background_executor().clone();
 2210                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2211                let snapshot = self.buffer().read(cx).snapshot(cx);
 2212                let selections = selections.clone();
 2213                self.serialize_selections = cx.background_spawn(async move {
 2214                    background_executor.timer(Duration::from_millis(100)).await;
 2215                    let selections = selections
 2216                        .iter()
 2217                        .map(|selection| {
 2218                            (
 2219                                selection.start.to_offset(&snapshot),
 2220                                selection.end.to_offset(&snapshot),
 2221                            )
 2222                        })
 2223                        .collect();
 2224                    DB.save_editor_selections(editor_id, workspace_id, selections)
 2225                        .await
 2226                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2227                        .log_err();
 2228                });
 2229            }
 2230        }
 2231
 2232        cx.notify();
 2233    }
 2234
 2235    pub fn change_selections<R>(
 2236        &mut self,
 2237        autoscroll: Option<Autoscroll>,
 2238        window: &mut Window,
 2239        cx: &mut Context<Self>,
 2240        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2241    ) -> R {
 2242        self.change_selections_inner(autoscroll, true, window, cx, change)
 2243    }
 2244
 2245    fn change_selections_inner<R>(
 2246        &mut self,
 2247        autoscroll: Option<Autoscroll>,
 2248        request_completions: bool,
 2249        window: &mut Window,
 2250        cx: &mut Context<Self>,
 2251        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2252    ) -> R {
 2253        let old_cursor_position = self.selections.newest_anchor().head();
 2254        self.push_to_selection_history();
 2255
 2256        let (changed, result) = self.selections.change_with(cx, change);
 2257
 2258        if changed {
 2259            if let Some(autoscroll) = autoscroll {
 2260                self.request_autoscroll(autoscroll, cx);
 2261            }
 2262            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2263
 2264            if self.should_open_signature_help_automatically(
 2265                &old_cursor_position,
 2266                self.signature_help_state.backspace_pressed(),
 2267                cx,
 2268            ) {
 2269                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2270            }
 2271            self.signature_help_state.set_backspace_pressed(false);
 2272        }
 2273
 2274        result
 2275    }
 2276
 2277    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2278    where
 2279        I: IntoIterator<Item = (Range<S>, T)>,
 2280        S: ToOffset,
 2281        T: Into<Arc<str>>,
 2282    {
 2283        if self.read_only(cx) {
 2284            return;
 2285        }
 2286
 2287        self.buffer
 2288            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2289    }
 2290
 2291    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2292    where
 2293        I: IntoIterator<Item = (Range<S>, T)>,
 2294        S: ToOffset,
 2295        T: Into<Arc<str>>,
 2296    {
 2297        if self.read_only(cx) {
 2298            return;
 2299        }
 2300
 2301        self.buffer.update(cx, |buffer, cx| {
 2302            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2303        });
 2304    }
 2305
 2306    pub fn edit_with_block_indent<I, S, T>(
 2307        &mut self,
 2308        edits: I,
 2309        original_start_columns: Vec<u32>,
 2310        cx: &mut Context<Self>,
 2311    ) where
 2312        I: IntoIterator<Item = (Range<S>, T)>,
 2313        S: ToOffset,
 2314        T: Into<Arc<str>>,
 2315    {
 2316        if self.read_only(cx) {
 2317            return;
 2318        }
 2319
 2320        self.buffer.update(cx, |buffer, cx| {
 2321            buffer.edit(
 2322                edits,
 2323                Some(AutoindentMode::Block {
 2324                    original_start_columns,
 2325                }),
 2326                cx,
 2327            )
 2328        });
 2329    }
 2330
 2331    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2332        self.hide_context_menu(window, cx);
 2333
 2334        match phase {
 2335            SelectPhase::Begin {
 2336                position,
 2337                add,
 2338                click_count,
 2339            } => self.begin_selection(position, add, click_count, window, cx),
 2340            SelectPhase::BeginColumnar {
 2341                position,
 2342                goal_column,
 2343                reset,
 2344            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 2345            SelectPhase::Extend {
 2346                position,
 2347                click_count,
 2348            } => self.extend_selection(position, click_count, window, cx),
 2349            SelectPhase::Update {
 2350                position,
 2351                goal_column,
 2352                scroll_delta,
 2353            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 2354            SelectPhase::End => self.end_selection(window, cx),
 2355        }
 2356    }
 2357
 2358    fn extend_selection(
 2359        &mut self,
 2360        position: DisplayPoint,
 2361        click_count: usize,
 2362        window: &mut Window,
 2363        cx: &mut Context<Self>,
 2364    ) {
 2365        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2366        let tail = self.selections.newest::<usize>(cx).tail();
 2367        self.begin_selection(position, false, click_count, window, cx);
 2368
 2369        let position = position.to_offset(&display_map, Bias::Left);
 2370        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 2371
 2372        let mut pending_selection = self
 2373            .selections
 2374            .pending_anchor()
 2375            .expect("extend_selection not called with pending selection");
 2376        if position >= tail {
 2377            pending_selection.start = tail_anchor;
 2378        } else {
 2379            pending_selection.end = tail_anchor;
 2380            pending_selection.reversed = true;
 2381        }
 2382
 2383        let mut pending_mode = self.selections.pending_mode().unwrap();
 2384        match &mut pending_mode {
 2385            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 2386            _ => {}
 2387        }
 2388
 2389        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 2390            s.set_pending(pending_selection, pending_mode)
 2391        });
 2392    }
 2393
 2394    fn begin_selection(
 2395        &mut self,
 2396        position: DisplayPoint,
 2397        add: bool,
 2398        click_count: usize,
 2399        window: &mut Window,
 2400        cx: &mut Context<Self>,
 2401    ) {
 2402        if !self.focus_handle.is_focused(window) {
 2403            self.last_focused_descendant = None;
 2404            window.focus(&self.focus_handle);
 2405        }
 2406
 2407        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2408        let buffer = &display_map.buffer_snapshot;
 2409        let newest_selection = self.selections.newest_anchor().clone();
 2410        let position = display_map.clip_point(position, Bias::Left);
 2411
 2412        let start;
 2413        let end;
 2414        let mode;
 2415        let mut auto_scroll;
 2416        match click_count {
 2417            1 => {
 2418                start = buffer.anchor_before(position.to_point(&display_map));
 2419                end = start;
 2420                mode = SelectMode::Character;
 2421                auto_scroll = true;
 2422            }
 2423            2 => {
 2424                let range = movement::surrounding_word(&display_map, position);
 2425                start = buffer.anchor_before(range.start.to_point(&display_map));
 2426                end = buffer.anchor_before(range.end.to_point(&display_map));
 2427                mode = SelectMode::Word(start..end);
 2428                auto_scroll = true;
 2429            }
 2430            3 => {
 2431                let position = display_map
 2432                    .clip_point(position, Bias::Left)
 2433                    .to_point(&display_map);
 2434                let line_start = display_map.prev_line_boundary(position).0;
 2435                let next_line_start = buffer.clip_point(
 2436                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2437                    Bias::Left,
 2438                );
 2439                start = buffer.anchor_before(line_start);
 2440                end = buffer.anchor_before(next_line_start);
 2441                mode = SelectMode::Line(start..end);
 2442                auto_scroll = true;
 2443            }
 2444            _ => {
 2445                start = buffer.anchor_before(0);
 2446                end = buffer.anchor_before(buffer.len());
 2447                mode = SelectMode::All;
 2448                auto_scroll = false;
 2449            }
 2450        }
 2451        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 2452
 2453        let point_to_delete: Option<usize> = {
 2454            let selected_points: Vec<Selection<Point>> =
 2455                self.selections.disjoint_in_range(start..end, cx);
 2456
 2457            if !add || click_count > 1 {
 2458                None
 2459            } else if !selected_points.is_empty() {
 2460                Some(selected_points[0].id)
 2461            } else {
 2462                let clicked_point_already_selected =
 2463                    self.selections.disjoint.iter().find(|selection| {
 2464                        selection.start.to_point(buffer) == start.to_point(buffer)
 2465                            || selection.end.to_point(buffer) == end.to_point(buffer)
 2466                    });
 2467
 2468                clicked_point_already_selected.map(|selection| selection.id)
 2469            }
 2470        };
 2471
 2472        let selections_count = self.selections.count();
 2473
 2474        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 2475            if let Some(point_to_delete) = point_to_delete {
 2476                s.delete(point_to_delete);
 2477
 2478                if selections_count == 1 {
 2479                    s.set_pending_anchor_range(start..end, mode);
 2480                }
 2481            } else {
 2482                if !add {
 2483                    s.clear_disjoint();
 2484                } else if click_count > 1 {
 2485                    s.delete(newest_selection.id)
 2486                }
 2487
 2488                s.set_pending_anchor_range(start..end, mode);
 2489            }
 2490        });
 2491    }
 2492
 2493    fn begin_columnar_selection(
 2494        &mut self,
 2495        position: DisplayPoint,
 2496        goal_column: u32,
 2497        reset: bool,
 2498        window: &mut Window,
 2499        cx: &mut Context<Self>,
 2500    ) {
 2501        if !self.focus_handle.is_focused(window) {
 2502            self.last_focused_descendant = None;
 2503            window.focus(&self.focus_handle);
 2504        }
 2505
 2506        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2507
 2508        if reset {
 2509            let pointer_position = display_map
 2510                .buffer_snapshot
 2511                .anchor_before(position.to_point(&display_map));
 2512
 2513            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 2514                s.clear_disjoint();
 2515                s.set_pending_anchor_range(
 2516                    pointer_position..pointer_position,
 2517                    SelectMode::Character,
 2518                );
 2519            });
 2520        }
 2521
 2522        let tail = self.selections.newest::<Point>(cx).tail();
 2523        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 2524
 2525        if !reset {
 2526            self.select_columns(
 2527                tail.to_display_point(&display_map),
 2528                position,
 2529                goal_column,
 2530                &display_map,
 2531                window,
 2532                cx,
 2533            );
 2534        }
 2535    }
 2536
 2537    fn update_selection(
 2538        &mut self,
 2539        position: DisplayPoint,
 2540        goal_column: u32,
 2541        scroll_delta: gpui::Point<f32>,
 2542        window: &mut Window,
 2543        cx: &mut Context<Self>,
 2544    ) {
 2545        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2546
 2547        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 2548            let tail = tail.to_display_point(&display_map);
 2549            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 2550        } else if let Some(mut pending) = self.selections.pending_anchor() {
 2551            let buffer = self.buffer.read(cx).snapshot(cx);
 2552            let head;
 2553            let tail;
 2554            let mode = self.selections.pending_mode().unwrap();
 2555            match &mode {
 2556                SelectMode::Character => {
 2557                    head = position.to_point(&display_map);
 2558                    tail = pending.tail().to_point(&buffer);
 2559                }
 2560                SelectMode::Word(original_range) => {
 2561                    let original_display_range = original_range.start.to_display_point(&display_map)
 2562                        ..original_range.end.to_display_point(&display_map);
 2563                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 2564                        ..original_display_range.end.to_point(&display_map);
 2565                    if movement::is_inside_word(&display_map, position)
 2566                        || original_display_range.contains(&position)
 2567                    {
 2568                        let word_range = movement::surrounding_word(&display_map, position);
 2569                        if word_range.start < original_display_range.start {
 2570                            head = word_range.start.to_point(&display_map);
 2571                        } else {
 2572                            head = word_range.end.to_point(&display_map);
 2573                        }
 2574                    } else {
 2575                        head = position.to_point(&display_map);
 2576                    }
 2577
 2578                    if head <= original_buffer_range.start {
 2579                        tail = original_buffer_range.end;
 2580                    } else {
 2581                        tail = original_buffer_range.start;
 2582                    }
 2583                }
 2584                SelectMode::Line(original_range) => {
 2585                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 2586
 2587                    let position = display_map
 2588                        .clip_point(position, Bias::Left)
 2589                        .to_point(&display_map);
 2590                    let line_start = display_map.prev_line_boundary(position).0;
 2591                    let next_line_start = buffer.clip_point(
 2592                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2593                        Bias::Left,
 2594                    );
 2595
 2596                    if line_start < original_range.start {
 2597                        head = line_start
 2598                    } else {
 2599                        head = next_line_start
 2600                    }
 2601
 2602                    if head <= original_range.start {
 2603                        tail = original_range.end;
 2604                    } else {
 2605                        tail = original_range.start;
 2606                    }
 2607                }
 2608                SelectMode::All => {
 2609                    return;
 2610                }
 2611            };
 2612
 2613            if head < tail {
 2614                pending.start = buffer.anchor_before(head);
 2615                pending.end = buffer.anchor_before(tail);
 2616                pending.reversed = true;
 2617            } else {
 2618                pending.start = buffer.anchor_before(tail);
 2619                pending.end = buffer.anchor_before(head);
 2620                pending.reversed = false;
 2621            }
 2622
 2623            self.change_selections(None, window, cx, |s| {
 2624                s.set_pending(pending, mode);
 2625            });
 2626        } else {
 2627            log::error!("update_selection dispatched with no pending selection");
 2628            return;
 2629        }
 2630
 2631        self.apply_scroll_delta(scroll_delta, window, cx);
 2632        cx.notify();
 2633    }
 2634
 2635    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 2636        self.columnar_selection_tail.take();
 2637        if self.selections.pending_anchor().is_some() {
 2638            let selections = self.selections.all::<usize>(cx);
 2639            self.change_selections(None, window, cx, |s| {
 2640                s.select(selections);
 2641                s.clear_pending();
 2642            });
 2643        }
 2644    }
 2645
 2646    fn select_columns(
 2647        &mut self,
 2648        tail: DisplayPoint,
 2649        head: DisplayPoint,
 2650        goal_column: u32,
 2651        display_map: &DisplaySnapshot,
 2652        window: &mut Window,
 2653        cx: &mut Context<Self>,
 2654    ) {
 2655        let start_row = cmp::min(tail.row(), head.row());
 2656        let end_row = cmp::max(tail.row(), head.row());
 2657        let start_column = cmp::min(tail.column(), goal_column);
 2658        let end_column = cmp::max(tail.column(), goal_column);
 2659        let reversed = start_column < tail.column();
 2660
 2661        let selection_ranges = (start_row.0..=end_row.0)
 2662            .map(DisplayRow)
 2663            .filter_map(|row| {
 2664                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 2665                    let start = display_map
 2666                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 2667                        .to_point(display_map);
 2668                    let end = display_map
 2669                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 2670                        .to_point(display_map);
 2671                    if reversed {
 2672                        Some(end..start)
 2673                    } else {
 2674                        Some(start..end)
 2675                    }
 2676                } else {
 2677                    None
 2678                }
 2679            })
 2680            .collect::<Vec<_>>();
 2681
 2682        self.change_selections(None, window, cx, |s| {
 2683            s.select_ranges(selection_ranges);
 2684        });
 2685        cx.notify();
 2686    }
 2687
 2688    pub fn has_pending_nonempty_selection(&self) -> bool {
 2689        let pending_nonempty_selection = match self.selections.pending_anchor() {
 2690            Some(Selection { start, end, .. }) => start != end,
 2691            None => false,
 2692        };
 2693
 2694        pending_nonempty_selection
 2695            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 2696    }
 2697
 2698    pub fn has_pending_selection(&self) -> bool {
 2699        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 2700    }
 2701
 2702    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 2703        self.selection_mark_mode = false;
 2704
 2705        if self.clear_expanded_diff_hunks(cx) {
 2706            cx.notify();
 2707            return;
 2708        }
 2709        if self.dismiss_menus_and_popups(true, window, cx) {
 2710            return;
 2711        }
 2712
 2713        if self.mode == EditorMode::Full
 2714            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 2715        {
 2716            return;
 2717        }
 2718
 2719        cx.propagate();
 2720    }
 2721
 2722    pub fn dismiss_menus_and_popups(
 2723        &mut self,
 2724        is_user_requested: bool,
 2725        window: &mut Window,
 2726        cx: &mut Context<Self>,
 2727    ) -> bool {
 2728        if self.take_rename(false, window, cx).is_some() {
 2729            return true;
 2730        }
 2731
 2732        if hide_hover(self, cx) {
 2733            return true;
 2734        }
 2735
 2736        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 2737            return true;
 2738        }
 2739
 2740        if self.hide_context_menu(window, cx).is_some() {
 2741            return true;
 2742        }
 2743
 2744        if self.mouse_context_menu.take().is_some() {
 2745            return true;
 2746        }
 2747
 2748        if is_user_requested && self.discard_inline_completion(true, cx) {
 2749            return true;
 2750        }
 2751
 2752        if self.snippet_stack.pop().is_some() {
 2753            return true;
 2754        }
 2755
 2756        if self.mode == EditorMode::Full && self.active_diagnostics.is_some() {
 2757            self.dismiss_diagnostics(cx);
 2758            return true;
 2759        }
 2760
 2761        false
 2762    }
 2763
 2764    fn linked_editing_ranges_for(
 2765        &self,
 2766        selection: Range<text::Anchor>,
 2767        cx: &App,
 2768    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 2769        if self.linked_edit_ranges.is_empty() {
 2770            return None;
 2771        }
 2772        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 2773            selection.end.buffer_id.and_then(|end_buffer_id| {
 2774                if selection.start.buffer_id != Some(end_buffer_id) {
 2775                    return None;
 2776                }
 2777                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 2778                let snapshot = buffer.read(cx).snapshot();
 2779                self.linked_edit_ranges
 2780                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 2781                    .map(|ranges| (ranges, snapshot, buffer))
 2782            })?;
 2783        use text::ToOffset as TO;
 2784        // find offset from the start of current range to current cursor position
 2785        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 2786
 2787        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 2788        let start_difference = start_offset - start_byte_offset;
 2789        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 2790        let end_difference = end_offset - start_byte_offset;
 2791        // Current range has associated linked ranges.
 2792        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 2793        for range in linked_ranges.iter() {
 2794            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 2795            let end_offset = start_offset + end_difference;
 2796            let start_offset = start_offset + start_difference;
 2797            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 2798                continue;
 2799            }
 2800            if self.selections.disjoint_anchor_ranges().any(|s| {
 2801                if s.start.buffer_id != selection.start.buffer_id
 2802                    || s.end.buffer_id != selection.end.buffer_id
 2803                {
 2804                    return false;
 2805                }
 2806                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 2807                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 2808            }) {
 2809                continue;
 2810            }
 2811            let start = buffer_snapshot.anchor_after(start_offset);
 2812            let end = buffer_snapshot.anchor_after(end_offset);
 2813            linked_edits
 2814                .entry(buffer.clone())
 2815                .or_default()
 2816                .push(start..end);
 2817        }
 2818        Some(linked_edits)
 2819    }
 2820
 2821    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 2822        let text: Arc<str> = text.into();
 2823
 2824        if self.read_only(cx) {
 2825            return;
 2826        }
 2827
 2828        let selections = self.selections.all_adjusted(cx);
 2829        let mut bracket_inserted = false;
 2830        let mut edits = Vec::new();
 2831        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 2832        let mut new_selections = Vec::with_capacity(selections.len());
 2833        let mut new_autoclose_regions = Vec::new();
 2834        let snapshot = self.buffer.read(cx).read(cx);
 2835
 2836        for (selection, autoclose_region) in
 2837            self.selections_with_autoclose_regions(selections, &snapshot)
 2838        {
 2839            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 2840                // Determine if the inserted text matches the opening or closing
 2841                // bracket of any of this language's bracket pairs.
 2842                let mut bracket_pair = None;
 2843                let mut is_bracket_pair_start = false;
 2844                let mut is_bracket_pair_end = false;
 2845                if !text.is_empty() {
 2846                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 2847                    //  and they are removing the character that triggered IME popup.
 2848                    for (pair, enabled) in scope.brackets() {
 2849                        if !pair.close && !pair.surround {
 2850                            continue;
 2851                        }
 2852
 2853                        if enabled && pair.start.ends_with(text.as_ref()) {
 2854                            let prefix_len = pair.start.len() - text.len();
 2855                            let preceding_text_matches_prefix = prefix_len == 0
 2856                                || (selection.start.column >= (prefix_len as u32)
 2857                                    && snapshot.contains_str_at(
 2858                                        Point::new(
 2859                                            selection.start.row,
 2860                                            selection.start.column - (prefix_len as u32),
 2861                                        ),
 2862                                        &pair.start[..prefix_len],
 2863                                    ));
 2864                            if preceding_text_matches_prefix {
 2865                                bracket_pair = Some(pair.clone());
 2866                                is_bracket_pair_start = true;
 2867                                break;
 2868                            }
 2869                        }
 2870                        if pair.end.as_str() == text.as_ref() {
 2871                            bracket_pair = Some(pair.clone());
 2872                            is_bracket_pair_end = true;
 2873                            break;
 2874                        }
 2875                    }
 2876                }
 2877
 2878                if let Some(bracket_pair) = bracket_pair {
 2879                    let snapshot_settings = snapshot.settings_at(selection.start, cx);
 2880                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 2881                    let auto_surround =
 2882                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 2883                    if selection.is_empty() {
 2884                        if is_bracket_pair_start {
 2885                            // If the inserted text is a suffix of an opening bracket and the
 2886                            // selection is preceded by the rest of the opening bracket, then
 2887                            // insert the closing bracket.
 2888                            let following_text_allows_autoclose = snapshot
 2889                                .chars_at(selection.start)
 2890                                .next()
 2891                                .map_or(true, |c| scope.should_autoclose_before(c));
 2892
 2893                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 2894                                && bracket_pair.start.len() == 1
 2895                            {
 2896                                let target = bracket_pair.start.chars().next().unwrap();
 2897                                let current_line_count = snapshot
 2898                                    .reversed_chars_at(selection.start)
 2899                                    .take_while(|&c| c != '\n')
 2900                                    .filter(|&c| c == target)
 2901                                    .count();
 2902                                current_line_count % 2 == 1
 2903                            } else {
 2904                                false
 2905                            };
 2906
 2907                            if autoclose
 2908                                && bracket_pair.close
 2909                                && following_text_allows_autoclose
 2910                                && !is_closing_quote
 2911                            {
 2912                                let anchor = snapshot.anchor_before(selection.end);
 2913                                new_selections.push((selection.map(|_| anchor), text.len()));
 2914                                new_autoclose_regions.push((
 2915                                    anchor,
 2916                                    text.len(),
 2917                                    selection.id,
 2918                                    bracket_pair.clone(),
 2919                                ));
 2920                                edits.push((
 2921                                    selection.range(),
 2922                                    format!("{}{}", text, bracket_pair.end).into(),
 2923                                ));
 2924                                bracket_inserted = true;
 2925                                continue;
 2926                            }
 2927                        }
 2928
 2929                        if let Some(region) = autoclose_region {
 2930                            // If the selection is followed by an auto-inserted closing bracket,
 2931                            // then don't insert that closing bracket again; just move the selection
 2932                            // past the closing bracket.
 2933                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 2934                                && text.as_ref() == region.pair.end.as_str();
 2935                            if should_skip {
 2936                                let anchor = snapshot.anchor_after(selection.end);
 2937                                new_selections
 2938                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 2939                                continue;
 2940                            }
 2941                        }
 2942
 2943                        let always_treat_brackets_as_autoclosed = snapshot
 2944                            .settings_at(selection.start, cx)
 2945                            .always_treat_brackets_as_autoclosed;
 2946                        if always_treat_brackets_as_autoclosed
 2947                            && is_bracket_pair_end
 2948                            && snapshot.contains_str_at(selection.end, text.as_ref())
 2949                        {
 2950                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 2951                            // and the inserted text is a closing bracket and the selection is followed
 2952                            // by the closing bracket then move the selection past the closing bracket.
 2953                            let anchor = snapshot.anchor_after(selection.end);
 2954                            new_selections.push((selection.map(|_| anchor), text.len()));
 2955                            continue;
 2956                        }
 2957                    }
 2958                    // If an opening bracket is 1 character long and is typed while
 2959                    // text is selected, then surround that text with the bracket pair.
 2960                    else if auto_surround
 2961                        && bracket_pair.surround
 2962                        && is_bracket_pair_start
 2963                        && bracket_pair.start.chars().count() == 1
 2964                    {
 2965                        edits.push((selection.start..selection.start, text.clone()));
 2966                        edits.push((
 2967                            selection.end..selection.end,
 2968                            bracket_pair.end.as_str().into(),
 2969                        ));
 2970                        bracket_inserted = true;
 2971                        new_selections.push((
 2972                            Selection {
 2973                                id: selection.id,
 2974                                start: snapshot.anchor_after(selection.start),
 2975                                end: snapshot.anchor_before(selection.end),
 2976                                reversed: selection.reversed,
 2977                                goal: selection.goal,
 2978                            },
 2979                            0,
 2980                        ));
 2981                        continue;
 2982                    }
 2983                }
 2984            }
 2985
 2986            if self.auto_replace_emoji_shortcode
 2987                && selection.is_empty()
 2988                && text.as_ref().ends_with(':')
 2989            {
 2990                if let Some(possible_emoji_short_code) =
 2991                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 2992                {
 2993                    if !possible_emoji_short_code.is_empty() {
 2994                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 2995                            let emoji_shortcode_start = Point::new(
 2996                                selection.start.row,
 2997                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 2998                            );
 2999
 3000                            // Remove shortcode from buffer
 3001                            edits.push((
 3002                                emoji_shortcode_start..selection.start,
 3003                                "".to_string().into(),
 3004                            ));
 3005                            new_selections.push((
 3006                                Selection {
 3007                                    id: selection.id,
 3008                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3009                                    end: snapshot.anchor_before(selection.start),
 3010                                    reversed: selection.reversed,
 3011                                    goal: selection.goal,
 3012                                },
 3013                                0,
 3014                            ));
 3015
 3016                            // Insert emoji
 3017                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3018                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3019                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3020
 3021                            continue;
 3022                        }
 3023                    }
 3024                }
 3025            }
 3026
 3027            // If not handling any auto-close operation, then just replace the selected
 3028            // text with the given input and move the selection to the end of the
 3029            // newly inserted text.
 3030            let anchor = snapshot.anchor_after(selection.end);
 3031            if !self.linked_edit_ranges.is_empty() {
 3032                let start_anchor = snapshot.anchor_before(selection.start);
 3033
 3034                let is_word_char = text.chars().next().map_or(true, |char| {
 3035                    let classifier = snapshot.char_classifier_at(start_anchor.to_offset(&snapshot));
 3036                    classifier.is_word(char)
 3037                });
 3038
 3039                if is_word_char {
 3040                    if let Some(ranges) = self
 3041                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3042                    {
 3043                        for (buffer, edits) in ranges {
 3044                            linked_edits
 3045                                .entry(buffer.clone())
 3046                                .or_default()
 3047                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3048                        }
 3049                    }
 3050                }
 3051            }
 3052
 3053            new_selections.push((selection.map(|_| anchor), 0));
 3054            edits.push((selection.start..selection.end, text.clone()));
 3055        }
 3056
 3057        drop(snapshot);
 3058
 3059        self.transact(window, cx, |this, window, cx| {
 3060            this.buffer.update(cx, |buffer, cx| {
 3061                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3062            });
 3063            for (buffer, edits) in linked_edits {
 3064                buffer.update(cx, |buffer, cx| {
 3065                    let snapshot = buffer.snapshot();
 3066                    let edits = edits
 3067                        .into_iter()
 3068                        .map(|(range, text)| {
 3069                            use text::ToPoint as TP;
 3070                            let end_point = TP::to_point(&range.end, &snapshot);
 3071                            let start_point = TP::to_point(&range.start, &snapshot);
 3072                            (start_point..end_point, text)
 3073                        })
 3074                        .sorted_by_key(|(range, _)| range.start)
 3075                        .collect::<Vec<_>>();
 3076                    buffer.edit(edits, None, cx);
 3077                })
 3078            }
 3079            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3080            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3081            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3082            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3083                .zip(new_selection_deltas)
 3084                .map(|(selection, delta)| Selection {
 3085                    id: selection.id,
 3086                    start: selection.start + delta,
 3087                    end: selection.end + delta,
 3088                    reversed: selection.reversed,
 3089                    goal: SelectionGoal::None,
 3090                })
 3091                .collect::<Vec<_>>();
 3092
 3093            let mut i = 0;
 3094            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3095                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3096                let start = map.buffer_snapshot.anchor_before(position);
 3097                let end = map.buffer_snapshot.anchor_after(position);
 3098                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3099                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3100                        Ordering::Less => i += 1,
 3101                        Ordering::Greater => break,
 3102                        Ordering::Equal => {
 3103                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3104                                Ordering::Less => i += 1,
 3105                                Ordering::Equal => break,
 3106                                Ordering::Greater => break,
 3107                            }
 3108                        }
 3109                    }
 3110                }
 3111                this.autoclose_regions.insert(
 3112                    i,
 3113                    AutocloseRegion {
 3114                        selection_id,
 3115                        range: start..end,
 3116                        pair,
 3117                    },
 3118                );
 3119            }
 3120
 3121            let had_active_inline_completion = this.has_active_inline_completion();
 3122            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3123                s.select(new_selections)
 3124            });
 3125
 3126            if !bracket_inserted {
 3127                if let Some(on_type_format_task) =
 3128                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3129                {
 3130                    on_type_format_task.detach_and_log_err(cx);
 3131                }
 3132            }
 3133
 3134            let editor_settings = EditorSettings::get_global(cx);
 3135            if bracket_inserted
 3136                && (editor_settings.auto_signature_help
 3137                    || editor_settings.show_signature_help_after_edits)
 3138            {
 3139                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3140            }
 3141
 3142            let trigger_in_words =
 3143                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3144            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3145            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3146            this.refresh_inline_completion(true, false, window, cx);
 3147        });
 3148    }
 3149
 3150    fn find_possible_emoji_shortcode_at_position(
 3151        snapshot: &MultiBufferSnapshot,
 3152        position: Point,
 3153    ) -> Option<String> {
 3154        let mut chars = Vec::new();
 3155        let mut found_colon = false;
 3156        for char in snapshot.reversed_chars_at(position).take(100) {
 3157            // Found a possible emoji shortcode in the middle of the buffer
 3158            if found_colon {
 3159                if char.is_whitespace() {
 3160                    chars.reverse();
 3161                    return Some(chars.iter().collect());
 3162                }
 3163                // If the previous character is not a whitespace, we are in the middle of a word
 3164                // and we only want to complete the shortcode if the word is made up of other emojis
 3165                let mut containing_word = String::new();
 3166                for ch in snapshot
 3167                    .reversed_chars_at(position)
 3168                    .skip(chars.len() + 1)
 3169                    .take(100)
 3170                {
 3171                    if ch.is_whitespace() {
 3172                        break;
 3173                    }
 3174                    containing_word.push(ch);
 3175                }
 3176                let containing_word = containing_word.chars().rev().collect::<String>();
 3177                if util::word_consists_of_emojis(containing_word.as_str()) {
 3178                    chars.reverse();
 3179                    return Some(chars.iter().collect());
 3180                }
 3181            }
 3182
 3183            if char.is_whitespace() || !char.is_ascii() {
 3184                return None;
 3185            }
 3186            if char == ':' {
 3187                found_colon = true;
 3188            } else {
 3189                chars.push(char);
 3190            }
 3191        }
 3192        // Found a possible emoji shortcode at the beginning of the buffer
 3193        chars.reverse();
 3194        Some(chars.iter().collect())
 3195    }
 3196
 3197    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3198        self.transact(window, cx, |this, window, cx| {
 3199            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
 3200                let selections = this.selections.all::<usize>(cx);
 3201                let multi_buffer = this.buffer.read(cx);
 3202                let buffer = multi_buffer.snapshot(cx);
 3203                selections
 3204                    .iter()
 3205                    .map(|selection| {
 3206                        let start_point = selection.start.to_point(&buffer);
 3207                        let mut indent =
 3208                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3209                        indent.len = cmp::min(indent.len, start_point.column);
 3210                        let start = selection.start;
 3211                        let end = selection.end;
 3212                        let selection_is_empty = start == end;
 3213                        let language_scope = buffer.language_scope_at(start);
 3214                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
 3215                            &language_scope
 3216                        {
 3217                            let insert_extra_newline =
 3218                                insert_extra_newline_brackets(&buffer, start..end, language)
 3219                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3220
 3221                            // Comment extension on newline is allowed only for cursor selections
 3222                            let comment_delimiter = maybe!({
 3223                                if !selection_is_empty {
 3224                                    return None;
 3225                                }
 3226
 3227                                if !multi_buffer.settings_at(0, cx).extend_comment_on_newline {
 3228                                    return None;
 3229                                }
 3230
 3231                                let delimiters = language.line_comment_prefixes();
 3232                                let max_len_of_delimiter =
 3233                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3234                                let (snapshot, range) =
 3235                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3236
 3237                                let mut index_of_first_non_whitespace = 0;
 3238                                let comment_candidate = snapshot
 3239                                    .chars_for_range(range)
 3240                                    .skip_while(|c| {
 3241                                        let should_skip = c.is_whitespace();
 3242                                        if should_skip {
 3243                                            index_of_first_non_whitespace += 1;
 3244                                        }
 3245                                        should_skip
 3246                                    })
 3247                                    .take(max_len_of_delimiter)
 3248                                    .collect::<String>();
 3249                                let comment_prefix = delimiters.iter().find(|comment_prefix| {
 3250                                    comment_candidate.starts_with(comment_prefix.as_ref())
 3251                                })?;
 3252                                let cursor_is_placed_after_comment_marker =
 3253                                    index_of_first_non_whitespace + comment_prefix.len()
 3254                                        <= start_point.column as usize;
 3255                                if cursor_is_placed_after_comment_marker {
 3256                                    Some(comment_prefix.clone())
 3257                                } else {
 3258                                    None
 3259                                }
 3260                            });
 3261                            (comment_delimiter, insert_extra_newline)
 3262                        } else {
 3263                            (None, false)
 3264                        };
 3265
 3266                        let capacity_for_delimiter = comment_delimiter
 3267                            .as_deref()
 3268                            .map(str::len)
 3269                            .unwrap_or_default();
 3270                        let mut new_text =
 3271                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
 3272                        new_text.push('\n');
 3273                        new_text.extend(indent.chars());
 3274                        if let Some(delimiter) = &comment_delimiter {
 3275                            new_text.push_str(delimiter);
 3276                        }
 3277                        if insert_extra_newline {
 3278                            new_text = new_text.repeat(2);
 3279                        }
 3280
 3281                        let anchor = buffer.anchor_after(end);
 3282                        let new_selection = selection.map(|_| anchor);
 3283                        (
 3284                            (start..end, new_text),
 3285                            (insert_extra_newline, new_selection),
 3286                        )
 3287                    })
 3288                    .unzip()
 3289            };
 3290
 3291            this.edit_with_autoindent(edits, cx);
 3292            let buffer = this.buffer.read(cx).snapshot(cx);
 3293            let new_selections = selection_fixup_info
 3294                .into_iter()
 3295                .map(|(extra_newline_inserted, new_selection)| {
 3296                    let mut cursor = new_selection.end.to_point(&buffer);
 3297                    if extra_newline_inserted {
 3298                        cursor.row -= 1;
 3299                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 3300                    }
 3301                    new_selection.map(|_| cursor)
 3302                })
 3303                .collect();
 3304
 3305            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3306                s.select(new_selections)
 3307            });
 3308            this.refresh_inline_completion(true, false, window, cx);
 3309        });
 3310    }
 3311
 3312    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 3313        let buffer = self.buffer.read(cx);
 3314        let snapshot = buffer.snapshot(cx);
 3315
 3316        let mut edits = Vec::new();
 3317        let mut rows = Vec::new();
 3318
 3319        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 3320            let cursor = selection.head();
 3321            let row = cursor.row;
 3322
 3323            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 3324
 3325            let newline = "\n".to_string();
 3326            edits.push((start_of_line..start_of_line, newline));
 3327
 3328            rows.push(row + rows_inserted as u32);
 3329        }
 3330
 3331        self.transact(window, cx, |editor, window, cx| {
 3332            editor.edit(edits, cx);
 3333
 3334            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3335                let mut index = 0;
 3336                s.move_cursors_with(|map, _, _| {
 3337                    let row = rows[index];
 3338                    index += 1;
 3339
 3340                    let point = Point::new(row, 0);
 3341                    let boundary = map.next_line_boundary(point).1;
 3342                    let clipped = map.clip_point(boundary, Bias::Left);
 3343
 3344                    (clipped, SelectionGoal::None)
 3345                });
 3346            });
 3347
 3348            let mut indent_edits = Vec::new();
 3349            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3350            for row in rows {
 3351                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3352                for (row, indent) in indents {
 3353                    if indent.len == 0 {
 3354                        continue;
 3355                    }
 3356
 3357                    let text = match indent.kind {
 3358                        IndentKind::Space => " ".repeat(indent.len as usize),
 3359                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3360                    };
 3361                    let point = Point::new(row.0, 0);
 3362                    indent_edits.push((point..point, text));
 3363                }
 3364            }
 3365            editor.edit(indent_edits, cx);
 3366        });
 3367    }
 3368
 3369    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 3370        let buffer = self.buffer.read(cx);
 3371        let snapshot = buffer.snapshot(cx);
 3372
 3373        let mut edits = Vec::new();
 3374        let mut rows = Vec::new();
 3375        let mut rows_inserted = 0;
 3376
 3377        for selection in self.selections.all_adjusted(cx) {
 3378            let cursor = selection.head();
 3379            let row = cursor.row;
 3380
 3381            let point = Point::new(row + 1, 0);
 3382            let start_of_line = snapshot.clip_point(point, Bias::Left);
 3383
 3384            let newline = "\n".to_string();
 3385            edits.push((start_of_line..start_of_line, newline));
 3386
 3387            rows_inserted += 1;
 3388            rows.push(row + rows_inserted);
 3389        }
 3390
 3391        self.transact(window, cx, |editor, window, cx| {
 3392            editor.edit(edits, cx);
 3393
 3394            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3395                let mut index = 0;
 3396                s.move_cursors_with(|map, _, _| {
 3397                    let row = rows[index];
 3398                    index += 1;
 3399
 3400                    let point = Point::new(row, 0);
 3401                    let boundary = map.next_line_boundary(point).1;
 3402                    let clipped = map.clip_point(boundary, Bias::Left);
 3403
 3404                    (clipped, SelectionGoal::None)
 3405                });
 3406            });
 3407
 3408            let mut indent_edits = Vec::new();
 3409            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 3410            for row in rows {
 3411                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 3412                for (row, indent) in indents {
 3413                    if indent.len == 0 {
 3414                        continue;
 3415                    }
 3416
 3417                    let text = match indent.kind {
 3418                        IndentKind::Space => " ".repeat(indent.len as usize),
 3419                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 3420                    };
 3421                    let point = Point::new(row.0, 0);
 3422                    indent_edits.push((point..point, text));
 3423                }
 3424            }
 3425            editor.edit(indent_edits, cx);
 3426        });
 3427    }
 3428
 3429    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3430        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 3431            original_start_columns: Vec::new(),
 3432        });
 3433        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 3434    }
 3435
 3436    fn insert_with_autoindent_mode(
 3437        &mut self,
 3438        text: &str,
 3439        autoindent_mode: Option<AutoindentMode>,
 3440        window: &mut Window,
 3441        cx: &mut Context<Self>,
 3442    ) {
 3443        if self.read_only(cx) {
 3444            return;
 3445        }
 3446
 3447        let text: Arc<str> = text.into();
 3448        self.transact(window, cx, |this, window, cx| {
 3449            let old_selections = this.selections.all_adjusted(cx);
 3450            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 3451                let anchors = {
 3452                    let snapshot = buffer.read(cx);
 3453                    old_selections
 3454                        .iter()
 3455                        .map(|s| {
 3456                            let anchor = snapshot.anchor_after(s.head());
 3457                            s.map(|_| anchor)
 3458                        })
 3459                        .collect::<Vec<_>>()
 3460                };
 3461                buffer.edit(
 3462                    old_selections
 3463                        .iter()
 3464                        .map(|s| (s.start..s.end, text.clone())),
 3465                    autoindent_mode,
 3466                    cx,
 3467                );
 3468                anchors
 3469            });
 3470
 3471            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 3472                s.select_anchors(selection_anchors);
 3473            });
 3474
 3475            cx.notify();
 3476        });
 3477    }
 3478
 3479    fn trigger_completion_on_input(
 3480        &mut self,
 3481        text: &str,
 3482        trigger_in_words: bool,
 3483        window: &mut Window,
 3484        cx: &mut Context<Self>,
 3485    ) {
 3486        if self.is_completion_trigger(text, trigger_in_words, cx) {
 3487            self.show_completions(
 3488                &ShowCompletions {
 3489                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 3490                },
 3491                window,
 3492                cx,
 3493            );
 3494        } else {
 3495            self.hide_context_menu(window, cx);
 3496        }
 3497    }
 3498
 3499    fn is_completion_trigger(
 3500        &self,
 3501        text: &str,
 3502        trigger_in_words: bool,
 3503        cx: &mut Context<Self>,
 3504    ) -> bool {
 3505        let position = self.selections.newest_anchor().head();
 3506        let multibuffer = self.buffer.read(cx);
 3507        let Some(buffer) = position
 3508            .buffer_id
 3509            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 3510        else {
 3511            return false;
 3512        };
 3513
 3514        if let Some(completion_provider) = &self.completion_provider {
 3515            completion_provider.is_completion_trigger(
 3516                &buffer,
 3517                position.text_anchor,
 3518                text,
 3519                trigger_in_words,
 3520                cx,
 3521            )
 3522        } else {
 3523            false
 3524        }
 3525    }
 3526
 3527    /// If any empty selections is touching the start of its innermost containing autoclose
 3528    /// region, expand it to select the brackets.
 3529    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3530        let selections = self.selections.all::<usize>(cx);
 3531        let buffer = self.buffer.read(cx).read(cx);
 3532        let new_selections = self
 3533            .selections_with_autoclose_regions(selections, &buffer)
 3534            .map(|(mut selection, region)| {
 3535                if !selection.is_empty() {
 3536                    return selection;
 3537                }
 3538
 3539                if let Some(region) = region {
 3540                    let mut range = region.range.to_offset(&buffer);
 3541                    if selection.start == range.start && range.start >= region.pair.start.len() {
 3542                        range.start -= region.pair.start.len();
 3543                        if buffer.contains_str_at(range.start, &region.pair.start)
 3544                            && buffer.contains_str_at(range.end, &region.pair.end)
 3545                        {
 3546                            range.end += region.pair.end.len();
 3547                            selection.start = range.start;
 3548                            selection.end = range.end;
 3549
 3550                            return selection;
 3551                        }
 3552                    }
 3553                }
 3554
 3555                let always_treat_brackets_as_autoclosed = buffer
 3556                    .settings_at(selection.start, cx)
 3557                    .always_treat_brackets_as_autoclosed;
 3558
 3559                if !always_treat_brackets_as_autoclosed {
 3560                    return selection;
 3561                }
 3562
 3563                if let Some(scope) = buffer.language_scope_at(selection.start) {
 3564                    for (pair, enabled) in scope.brackets() {
 3565                        if !enabled || !pair.close {
 3566                            continue;
 3567                        }
 3568
 3569                        if buffer.contains_str_at(selection.start, &pair.end) {
 3570                            let pair_start_len = pair.start.len();
 3571                            if buffer.contains_str_at(
 3572                                selection.start.saturating_sub(pair_start_len),
 3573                                &pair.start,
 3574                            ) {
 3575                                selection.start -= pair_start_len;
 3576                                selection.end += pair.end.len();
 3577
 3578                                return selection;
 3579                            }
 3580                        }
 3581                    }
 3582                }
 3583
 3584                selection
 3585            })
 3586            .collect();
 3587
 3588        drop(buffer);
 3589        self.change_selections(None, window, cx, |selections| {
 3590            selections.select(new_selections)
 3591        });
 3592    }
 3593
 3594    /// Iterate the given selections, and for each one, find the smallest surrounding
 3595    /// autoclose region. This uses the ordering of the selections and the autoclose
 3596    /// regions to avoid repeated comparisons.
 3597    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 3598        &'a self,
 3599        selections: impl IntoIterator<Item = Selection<D>>,
 3600        buffer: &'a MultiBufferSnapshot,
 3601    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 3602        let mut i = 0;
 3603        let mut regions = self.autoclose_regions.as_slice();
 3604        selections.into_iter().map(move |selection| {
 3605            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 3606
 3607            let mut enclosing = None;
 3608            while let Some(pair_state) = regions.get(i) {
 3609                if pair_state.range.end.to_offset(buffer) < range.start {
 3610                    regions = &regions[i + 1..];
 3611                    i = 0;
 3612                } else if pair_state.range.start.to_offset(buffer) > range.end {
 3613                    break;
 3614                } else {
 3615                    if pair_state.selection_id == selection.id {
 3616                        enclosing = Some(pair_state);
 3617                    }
 3618                    i += 1;
 3619                }
 3620            }
 3621
 3622            (selection, enclosing)
 3623        })
 3624    }
 3625
 3626    /// Remove any autoclose regions that no longer contain their selection.
 3627    fn invalidate_autoclose_regions(
 3628        &mut self,
 3629        mut selections: &[Selection<Anchor>],
 3630        buffer: &MultiBufferSnapshot,
 3631    ) {
 3632        self.autoclose_regions.retain(|state| {
 3633            let mut i = 0;
 3634            while let Some(selection) = selections.get(i) {
 3635                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 3636                    selections = &selections[1..];
 3637                    continue;
 3638                }
 3639                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 3640                    break;
 3641                }
 3642                if selection.id == state.selection_id {
 3643                    return true;
 3644                } else {
 3645                    i += 1;
 3646                }
 3647            }
 3648            false
 3649        });
 3650    }
 3651
 3652    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 3653        let offset = position.to_offset(buffer);
 3654        let (word_range, kind) = buffer.surrounding_word(offset, true);
 3655        if offset > word_range.start && kind == Some(CharKind::Word) {
 3656            Some(
 3657                buffer
 3658                    .text_for_range(word_range.start..offset)
 3659                    .collect::<String>(),
 3660            )
 3661        } else {
 3662            None
 3663        }
 3664    }
 3665
 3666    pub fn toggle_inlay_hints(
 3667        &mut self,
 3668        _: &ToggleInlayHints,
 3669        _: &mut Window,
 3670        cx: &mut Context<Self>,
 3671    ) {
 3672        self.refresh_inlay_hints(
 3673            InlayHintRefreshReason::Toggle(!self.inlay_hint_cache.enabled),
 3674            cx,
 3675        );
 3676    }
 3677
 3678    pub fn inlay_hints_enabled(&self) -> bool {
 3679        self.inlay_hint_cache.enabled
 3680    }
 3681
 3682    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 3683        if self.semantics_provider.is_none() || self.mode != EditorMode::Full {
 3684            return;
 3685        }
 3686
 3687        let reason_description = reason.description();
 3688        let ignore_debounce = matches!(
 3689            reason,
 3690            InlayHintRefreshReason::SettingsChange(_)
 3691                | InlayHintRefreshReason::Toggle(_)
 3692                | InlayHintRefreshReason::ExcerptsRemoved(_)
 3693        );
 3694        let (invalidate_cache, required_languages) = match reason {
 3695            InlayHintRefreshReason::Toggle(enabled) => {
 3696                if self.inlay_hint_cache.enabled == enabled {
 3697                    return;
 3698                }
 3699                self.inlay_hint_cache.enabled = enabled;
 3700                if enabled {
 3701                    (InvalidationStrategy::RefreshRequested, None)
 3702                } else {
 3703                    self.inlay_hint_cache.clear();
 3704                    self.splice_inlays(
 3705                        &self
 3706                            .visible_inlay_hints(cx)
 3707                            .iter()
 3708                            .map(|inlay| inlay.id)
 3709                            .collect::<Vec<InlayId>>(),
 3710                        Vec::new(),
 3711                        cx,
 3712                    );
 3713                    return;
 3714                }
 3715            }
 3716            InlayHintRefreshReason::SettingsChange(new_settings) => {
 3717                match self.inlay_hint_cache.update_settings(
 3718                    &self.buffer,
 3719                    new_settings,
 3720                    self.visible_inlay_hints(cx),
 3721                    cx,
 3722                ) {
 3723                    ControlFlow::Break(Some(InlaySplice {
 3724                        to_remove,
 3725                        to_insert,
 3726                    })) => {
 3727                        self.splice_inlays(&to_remove, to_insert, cx);
 3728                        return;
 3729                    }
 3730                    ControlFlow::Break(None) => return,
 3731                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 3732                }
 3733            }
 3734            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 3735                if let Some(InlaySplice {
 3736                    to_remove,
 3737                    to_insert,
 3738                }) = self.inlay_hint_cache.remove_excerpts(excerpts_removed)
 3739                {
 3740                    self.splice_inlays(&to_remove, to_insert, cx);
 3741                }
 3742                return;
 3743            }
 3744            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 3745            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 3746                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 3747            }
 3748            InlayHintRefreshReason::RefreshRequested => {
 3749                (InvalidationStrategy::RefreshRequested, None)
 3750            }
 3751        };
 3752
 3753        if let Some(InlaySplice {
 3754            to_remove,
 3755            to_insert,
 3756        }) = self.inlay_hint_cache.spawn_hint_refresh(
 3757            reason_description,
 3758            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 3759            invalidate_cache,
 3760            ignore_debounce,
 3761            cx,
 3762        ) {
 3763            self.splice_inlays(&to_remove, to_insert, cx);
 3764        }
 3765    }
 3766
 3767    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 3768        self.display_map
 3769            .read(cx)
 3770            .current_inlays()
 3771            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 3772            .cloned()
 3773            .collect()
 3774    }
 3775
 3776    pub fn excerpts_for_inlay_hints_query(
 3777        &self,
 3778        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 3779        cx: &mut Context<Editor>,
 3780    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 3781        let Some(project) = self.project.as_ref() else {
 3782            return HashMap::default();
 3783        };
 3784        let project = project.read(cx);
 3785        let multi_buffer = self.buffer().read(cx);
 3786        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 3787        let multi_buffer_visible_start = self
 3788            .scroll_manager
 3789            .anchor()
 3790            .anchor
 3791            .to_point(&multi_buffer_snapshot);
 3792        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 3793            multi_buffer_visible_start
 3794                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 3795            Bias::Left,
 3796        );
 3797        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 3798        multi_buffer_snapshot
 3799            .range_to_buffer_ranges(multi_buffer_visible_range)
 3800            .into_iter()
 3801            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 3802            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 3803                let buffer_file = project::File::from_dyn(buffer.file())?;
 3804                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 3805                let worktree_entry = buffer_worktree
 3806                    .read(cx)
 3807                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 3808                if worktree_entry.is_ignored {
 3809                    return None;
 3810                }
 3811
 3812                let language = buffer.language()?;
 3813                if let Some(restrict_to_languages) = restrict_to_languages {
 3814                    if !restrict_to_languages.contains(language) {
 3815                        return None;
 3816                    }
 3817                }
 3818                Some((
 3819                    excerpt_id,
 3820                    (
 3821                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 3822                        buffer.version().clone(),
 3823                        excerpt_visible_range,
 3824                    ),
 3825                ))
 3826            })
 3827            .collect()
 3828    }
 3829
 3830    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 3831        TextLayoutDetails {
 3832            text_system: window.text_system().clone(),
 3833            editor_style: self.style.clone().unwrap(),
 3834            rem_size: window.rem_size(),
 3835            scroll_anchor: self.scroll_manager.anchor(),
 3836            visible_rows: self.visible_line_count(),
 3837            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 3838        }
 3839    }
 3840
 3841    pub fn splice_inlays(
 3842        &self,
 3843        to_remove: &[InlayId],
 3844        to_insert: Vec<Inlay>,
 3845        cx: &mut Context<Self>,
 3846    ) {
 3847        self.display_map.update(cx, |display_map, cx| {
 3848            display_map.splice_inlays(to_remove, to_insert, cx)
 3849        });
 3850        cx.notify();
 3851    }
 3852
 3853    fn trigger_on_type_formatting(
 3854        &self,
 3855        input: String,
 3856        window: &mut Window,
 3857        cx: &mut Context<Self>,
 3858    ) -> Option<Task<Result<()>>> {
 3859        if input.len() != 1 {
 3860            return None;
 3861        }
 3862
 3863        let project = self.project.as_ref()?;
 3864        let position = self.selections.newest_anchor().head();
 3865        let (buffer, buffer_position) = self
 3866            .buffer
 3867            .read(cx)
 3868            .text_anchor_for_position(position, cx)?;
 3869
 3870        let settings = language_settings::language_settings(
 3871            buffer
 3872                .read(cx)
 3873                .language_at(buffer_position)
 3874                .map(|l| l.name()),
 3875            buffer.read(cx).file(),
 3876            cx,
 3877        );
 3878        if !settings.use_on_type_format {
 3879            return None;
 3880        }
 3881
 3882        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 3883        // hence we do LSP request & edit on host side only — add formats to host's history.
 3884        let push_to_lsp_host_history = true;
 3885        // If this is not the host, append its history with new edits.
 3886        let push_to_client_history = project.read(cx).is_via_collab();
 3887
 3888        let on_type_formatting = project.update(cx, |project, cx| {
 3889            project.on_type_format(
 3890                buffer.clone(),
 3891                buffer_position,
 3892                input,
 3893                push_to_lsp_host_history,
 3894                cx,
 3895            )
 3896        });
 3897        Some(cx.spawn_in(window, |editor, mut cx| async move {
 3898            if let Some(transaction) = on_type_formatting.await? {
 3899                if push_to_client_history {
 3900                    buffer
 3901                        .update(&mut cx, |buffer, _| {
 3902                            buffer.push_transaction(transaction, Instant::now());
 3903                        })
 3904                        .ok();
 3905                }
 3906                editor.update(&mut cx, |editor, cx| {
 3907                    editor.refresh_document_highlights(cx);
 3908                })?;
 3909            }
 3910            Ok(())
 3911        }))
 3912    }
 3913
 3914    pub fn show_completions(
 3915        &mut self,
 3916        options: &ShowCompletions,
 3917        window: &mut Window,
 3918        cx: &mut Context<Self>,
 3919    ) {
 3920        if self.pending_rename.is_some() {
 3921            return;
 3922        }
 3923
 3924        let Some(provider) = self.completion_provider.as_ref() else {
 3925            return;
 3926        };
 3927
 3928        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 3929            return;
 3930        }
 3931
 3932        let position = self.selections.newest_anchor().head();
 3933        if position.diff_base_anchor.is_some() {
 3934            return;
 3935        }
 3936        let (buffer, buffer_position) =
 3937            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 3938                output
 3939            } else {
 3940                return;
 3941            };
 3942        let show_completion_documentation = buffer
 3943            .read(cx)
 3944            .snapshot()
 3945            .settings_at(buffer_position, cx)
 3946            .show_completion_documentation;
 3947
 3948        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 3949
 3950        let trigger_kind = match &options.trigger {
 3951            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 3952                CompletionTriggerKind::TRIGGER_CHARACTER
 3953            }
 3954            _ => CompletionTriggerKind::INVOKED,
 3955        };
 3956        let completion_context = CompletionContext {
 3957            trigger_character: options.trigger.as_ref().and_then(|trigger| {
 3958                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 3959                    Some(String::from(trigger))
 3960                } else {
 3961                    None
 3962                }
 3963            }),
 3964            trigger_kind,
 3965        };
 3966        let completions =
 3967            provider.completions(&buffer, buffer_position, completion_context, window, cx);
 3968        let sort_completions = provider.sort_completions();
 3969
 3970        let id = post_inc(&mut self.next_completion_id);
 3971        let task = cx.spawn_in(window, |editor, mut cx| {
 3972            async move {
 3973                editor.update(&mut cx, |this, _| {
 3974                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 3975                })?;
 3976                let completions = completions.await.log_err();
 3977                let menu = if let Some(completions) = completions {
 3978                    let mut menu = CompletionsMenu::new(
 3979                        id,
 3980                        sort_completions,
 3981                        show_completion_documentation,
 3982                        position,
 3983                        buffer.clone(),
 3984                        completions.into(),
 3985                    );
 3986
 3987                    menu.filter(query.as_deref(), cx.background_executor().clone())
 3988                        .await;
 3989
 3990                    menu.visible().then_some(menu)
 3991                } else {
 3992                    None
 3993                };
 3994
 3995                editor.update_in(&mut cx, |editor, window, cx| {
 3996                    match editor.context_menu.borrow().as_ref() {
 3997                        None => {}
 3998                        Some(CodeContextMenu::Completions(prev_menu)) => {
 3999                            if prev_menu.id > id {
 4000                                return;
 4001                            }
 4002                        }
 4003                        _ => return,
 4004                    }
 4005
 4006                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 4007                        let mut menu = menu.unwrap();
 4008                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 4009
 4010                        *editor.context_menu.borrow_mut() =
 4011                            Some(CodeContextMenu::Completions(menu));
 4012
 4013                        if editor.show_edit_predictions_in_menu() {
 4014                            editor.update_visible_inline_completion(window, cx);
 4015                        } else {
 4016                            editor.discard_inline_completion(false, cx);
 4017                        }
 4018
 4019                        cx.notify();
 4020                    } else if editor.completion_tasks.len() <= 1 {
 4021                        // If there are no more completion tasks and the last menu was
 4022                        // empty, we should hide it.
 4023                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 4024                        // If it was already hidden and we don't show inline
 4025                        // completions in the menu, we should also show the
 4026                        // inline-completion when available.
 4027                        if was_hidden && editor.show_edit_predictions_in_menu() {
 4028                            editor.update_visible_inline_completion(window, cx);
 4029                        }
 4030                    }
 4031                })?;
 4032
 4033                Ok::<_, anyhow::Error>(())
 4034            }
 4035            .log_err()
 4036        });
 4037
 4038        self.completion_tasks.push((id, task));
 4039    }
 4040
 4041    pub fn confirm_completion(
 4042        &mut self,
 4043        action: &ConfirmCompletion,
 4044        window: &mut Window,
 4045        cx: &mut Context<Self>,
 4046    ) -> Option<Task<Result<()>>> {
 4047        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 4048    }
 4049
 4050    pub fn compose_completion(
 4051        &mut self,
 4052        action: &ComposeCompletion,
 4053        window: &mut Window,
 4054        cx: &mut Context<Self>,
 4055    ) -> Option<Task<Result<()>>> {
 4056        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 4057    }
 4058
 4059    fn do_completion(
 4060        &mut self,
 4061        item_ix: Option<usize>,
 4062        intent: CompletionIntent,
 4063        window: &mut Window,
 4064        cx: &mut Context<Editor>,
 4065    ) -> Option<Task<std::result::Result<(), anyhow::Error>>> {
 4066        use language::ToOffset as _;
 4067
 4068        let completions_menu =
 4069            if let CodeContextMenu::Completions(menu) = self.hide_context_menu(window, cx)? {
 4070                menu
 4071            } else {
 4072                return None;
 4073            };
 4074
 4075        let entries = completions_menu.entries.borrow();
 4076        let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 4077        if self.show_edit_predictions_in_menu() {
 4078            self.discard_inline_completion(true, cx);
 4079        }
 4080        let candidate_id = mat.candidate_id;
 4081        drop(entries);
 4082
 4083        let buffer_handle = completions_menu.buffer;
 4084        let completion = completions_menu
 4085            .completions
 4086            .borrow()
 4087            .get(candidate_id)?
 4088            .clone();
 4089        cx.stop_propagation();
 4090
 4091        let snippet;
 4092        let text;
 4093
 4094        if completion.is_snippet() {
 4095            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
 4096            text = snippet.as_ref().unwrap().text.clone();
 4097        } else {
 4098            snippet = None;
 4099            text = completion.new_text.clone();
 4100        };
 4101        let selections = self.selections.all::<usize>(cx);
 4102        let buffer = buffer_handle.read(cx);
 4103        let old_range = completion.old_range.to_offset(buffer);
 4104        let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
 4105
 4106        let newest_selection = self.selections.newest_anchor();
 4107        if newest_selection.start.buffer_id != Some(buffer_handle.read(cx).remote_id()) {
 4108            return None;
 4109        }
 4110
 4111        let lookbehind = newest_selection
 4112            .start
 4113            .text_anchor
 4114            .to_offset(buffer)
 4115            .saturating_sub(old_range.start);
 4116        let lookahead = old_range
 4117            .end
 4118            .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
 4119        let mut common_prefix_len = old_text
 4120            .bytes()
 4121            .zip(text.bytes())
 4122            .take_while(|(a, b)| a == b)
 4123            .count();
 4124
 4125        let snapshot = self.buffer.read(cx).snapshot(cx);
 4126        let mut range_to_replace: Option<Range<isize>> = None;
 4127        let mut ranges = Vec::new();
 4128        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4129        for selection in &selections {
 4130            if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
 4131                let start = selection.start.saturating_sub(lookbehind);
 4132                let end = selection.end + lookahead;
 4133                if selection.id == newest_selection.id {
 4134                    range_to_replace = Some(
 4135                        ((start + common_prefix_len) as isize - selection.start as isize)
 4136                            ..(end as isize - selection.start as isize),
 4137                    );
 4138                }
 4139                ranges.push(start + common_prefix_len..end);
 4140            } else {
 4141                common_prefix_len = 0;
 4142                ranges.clear();
 4143                ranges.extend(selections.iter().map(|s| {
 4144                    if s.id == newest_selection.id {
 4145                        range_to_replace = Some(
 4146                            old_range.start.to_offset_utf16(&snapshot).0 as isize
 4147                                - selection.start as isize
 4148                                ..old_range.end.to_offset_utf16(&snapshot).0 as isize
 4149                                    - selection.start as isize,
 4150                        );
 4151                        old_range.clone()
 4152                    } else {
 4153                        s.start..s.end
 4154                    }
 4155                }));
 4156                break;
 4157            }
 4158            if !self.linked_edit_ranges.is_empty() {
 4159                let start_anchor = snapshot.anchor_before(selection.head());
 4160                let end_anchor = snapshot.anchor_after(selection.tail());
 4161                if let Some(ranges) = self
 4162                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 4163                {
 4164                    for (buffer, edits) in ranges {
 4165                        linked_edits.entry(buffer.clone()).or_default().extend(
 4166                            edits
 4167                                .into_iter()
 4168                                .map(|range| (range, text[common_prefix_len..].to_owned())),
 4169                        );
 4170                    }
 4171                }
 4172            }
 4173        }
 4174        let text = &text[common_prefix_len..];
 4175
 4176        cx.emit(EditorEvent::InputHandled {
 4177            utf16_range_to_replace: range_to_replace,
 4178            text: text.into(),
 4179        });
 4180
 4181        self.transact(window, cx, |this, window, cx| {
 4182            if let Some(mut snippet) = snippet {
 4183                snippet.text = text.to_string();
 4184                for tabstop in snippet
 4185                    .tabstops
 4186                    .iter_mut()
 4187                    .flat_map(|tabstop| tabstop.ranges.iter_mut())
 4188                {
 4189                    tabstop.start -= common_prefix_len as isize;
 4190                    tabstop.end -= common_prefix_len as isize;
 4191                }
 4192
 4193                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 4194            } else {
 4195                this.buffer.update(cx, |buffer, cx| {
 4196                    buffer.edit(
 4197                        ranges.iter().map(|range| (range.clone(), text)),
 4198                        this.autoindent_mode.clone(),
 4199                        cx,
 4200                    );
 4201                });
 4202            }
 4203            for (buffer, edits) in linked_edits {
 4204                buffer.update(cx, |buffer, cx| {
 4205                    let snapshot = buffer.snapshot();
 4206                    let edits = edits
 4207                        .into_iter()
 4208                        .map(|(range, text)| {
 4209                            use text::ToPoint as TP;
 4210                            let end_point = TP::to_point(&range.end, &snapshot);
 4211                            let start_point = TP::to_point(&range.start, &snapshot);
 4212                            (start_point..end_point, text)
 4213                        })
 4214                        .sorted_by_key(|(range, _)| range.start)
 4215                        .collect::<Vec<_>>();
 4216                    buffer.edit(edits, None, cx);
 4217                })
 4218            }
 4219
 4220            this.refresh_inline_completion(true, false, window, cx);
 4221        });
 4222
 4223        let show_new_completions_on_confirm = completion
 4224            .confirm
 4225            .as_ref()
 4226            .map_or(false, |confirm| confirm(intent, window, cx));
 4227        if show_new_completions_on_confirm {
 4228            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 4229        }
 4230
 4231        let provider = self.completion_provider.as_ref()?;
 4232        drop(completion);
 4233        let apply_edits = provider.apply_additional_edits_for_completion(
 4234            buffer_handle,
 4235            completions_menu.completions.clone(),
 4236            candidate_id,
 4237            true,
 4238            cx,
 4239        );
 4240
 4241        let editor_settings = EditorSettings::get_global(cx);
 4242        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 4243            // After the code completion is finished, users often want to know what signatures are needed.
 4244            // so we should automatically call signature_help
 4245            self.show_signature_help(&ShowSignatureHelp, window, cx);
 4246        }
 4247
 4248        Some(cx.foreground_executor().spawn(async move {
 4249            apply_edits.await?;
 4250            Ok(())
 4251        }))
 4252    }
 4253
 4254    pub fn toggle_code_actions(
 4255        &mut self,
 4256        action: &ToggleCodeActions,
 4257        window: &mut Window,
 4258        cx: &mut Context<Self>,
 4259    ) {
 4260        let mut context_menu = self.context_menu.borrow_mut();
 4261        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 4262            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 4263                // Toggle if we're selecting the same one
 4264                *context_menu = None;
 4265                cx.notify();
 4266                return;
 4267            } else {
 4268                // Otherwise, clear it and start a new one
 4269                *context_menu = None;
 4270                cx.notify();
 4271            }
 4272        }
 4273        drop(context_menu);
 4274        let snapshot = self.snapshot(window, cx);
 4275        let deployed_from_indicator = action.deployed_from_indicator;
 4276        let mut task = self.code_actions_task.take();
 4277        let action = action.clone();
 4278        cx.spawn_in(window, |editor, mut cx| async move {
 4279            while let Some(prev_task) = task {
 4280                prev_task.await.log_err();
 4281                task = editor.update(&mut cx, |this, _| this.code_actions_task.take())?;
 4282            }
 4283
 4284            let spawned_test_task = editor.update_in(&mut cx, |editor, window, cx| {
 4285                if editor.focus_handle.is_focused(window) {
 4286                    let multibuffer_point = action
 4287                        .deployed_from_indicator
 4288                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 4289                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 4290                    let (buffer, buffer_row) = snapshot
 4291                        .buffer_snapshot
 4292                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 4293                        .and_then(|(buffer_snapshot, range)| {
 4294                            editor
 4295                                .buffer
 4296                                .read(cx)
 4297                                .buffer(buffer_snapshot.remote_id())
 4298                                .map(|buffer| (buffer, range.start.row))
 4299                        })?;
 4300                    let (_, code_actions) = editor
 4301                        .available_code_actions
 4302                        .clone()
 4303                        .and_then(|(location, code_actions)| {
 4304                            let snapshot = location.buffer.read(cx).snapshot();
 4305                            let point_range = location.range.to_point(&snapshot);
 4306                            let point_range = point_range.start.row..=point_range.end.row;
 4307                            if point_range.contains(&buffer_row) {
 4308                                Some((location, code_actions))
 4309                            } else {
 4310                                None
 4311                            }
 4312                        })
 4313                        .unzip();
 4314                    let buffer_id = buffer.read(cx).remote_id();
 4315                    let tasks = editor
 4316                        .tasks
 4317                        .get(&(buffer_id, buffer_row))
 4318                        .map(|t| Arc::new(t.to_owned()));
 4319                    if tasks.is_none() && code_actions.is_none() {
 4320                        return None;
 4321                    }
 4322
 4323                    editor.completion_tasks.clear();
 4324                    editor.discard_inline_completion(false, cx);
 4325                    let task_context =
 4326                        tasks
 4327                            .as_ref()
 4328                            .zip(editor.project.clone())
 4329                            .map(|(tasks, project)| {
 4330                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 4331                            });
 4332
 4333                    Some(cx.spawn_in(window, |editor, mut cx| async move {
 4334                        let task_context = match task_context {
 4335                            Some(task_context) => task_context.await,
 4336                            None => None,
 4337                        };
 4338                        let resolved_tasks =
 4339                            tasks.zip(task_context).map(|(tasks, task_context)| {
 4340                                Rc::new(ResolvedTasks {
 4341                                    templates: tasks.resolve(&task_context).collect(),
 4342                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 4343                                        multibuffer_point.row,
 4344                                        tasks.column,
 4345                                    )),
 4346                                })
 4347                            });
 4348                        let spawn_straight_away = resolved_tasks
 4349                            .as_ref()
 4350                            .map_or(false, |tasks| tasks.templates.len() == 1)
 4351                            && code_actions
 4352                                .as_ref()
 4353                                .map_or(true, |actions| actions.is_empty());
 4354                        if let Ok(task) = editor.update_in(&mut cx, |editor, window, cx| {
 4355                            *editor.context_menu.borrow_mut() =
 4356                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 4357                                    buffer,
 4358                                    actions: CodeActionContents {
 4359                                        tasks: resolved_tasks,
 4360                                        actions: code_actions,
 4361                                    },
 4362                                    selected_item: Default::default(),
 4363                                    scroll_handle: UniformListScrollHandle::default(),
 4364                                    deployed_from_indicator,
 4365                                }));
 4366                            if spawn_straight_away {
 4367                                if let Some(task) = editor.confirm_code_action(
 4368                                    &ConfirmCodeAction { item_ix: Some(0) },
 4369                                    window,
 4370                                    cx,
 4371                                ) {
 4372                                    cx.notify();
 4373                                    return task;
 4374                                }
 4375                            }
 4376                            cx.notify();
 4377                            Task::ready(Ok(()))
 4378                        }) {
 4379                            task.await
 4380                        } else {
 4381                            Ok(())
 4382                        }
 4383                    }))
 4384                } else {
 4385                    Some(Task::ready(Ok(())))
 4386                }
 4387            })?;
 4388            if let Some(task) = spawned_test_task {
 4389                task.await?;
 4390            }
 4391
 4392            Ok::<_, anyhow::Error>(())
 4393        })
 4394        .detach_and_log_err(cx);
 4395    }
 4396
 4397    pub fn confirm_code_action(
 4398        &mut self,
 4399        action: &ConfirmCodeAction,
 4400        window: &mut Window,
 4401        cx: &mut Context<Self>,
 4402    ) -> Option<Task<Result<()>>> {
 4403        let actions_menu =
 4404            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 4405                menu
 4406            } else {
 4407                return None;
 4408            };
 4409        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 4410        let action = actions_menu.actions.get(action_ix)?;
 4411        let title = action.label();
 4412        let buffer = actions_menu.buffer;
 4413        let workspace = self.workspace()?;
 4414
 4415        match action {
 4416            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 4417                workspace.update(cx, |workspace, cx| {
 4418                    workspace::tasks::schedule_resolved_task(
 4419                        workspace,
 4420                        task_source_kind,
 4421                        resolved_task,
 4422                        false,
 4423                        cx,
 4424                    );
 4425
 4426                    Some(Task::ready(Ok(())))
 4427                })
 4428            }
 4429            CodeActionsItem::CodeAction {
 4430                excerpt_id,
 4431                action,
 4432                provider,
 4433            } => {
 4434                let apply_code_action =
 4435                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 4436                let workspace = workspace.downgrade();
 4437                Some(cx.spawn_in(window, |editor, cx| async move {
 4438                    let project_transaction = apply_code_action.await?;
 4439                    Self::open_project_transaction(
 4440                        &editor,
 4441                        workspace,
 4442                        project_transaction,
 4443                        title,
 4444                        cx,
 4445                    )
 4446                    .await
 4447                }))
 4448            }
 4449        }
 4450    }
 4451
 4452    pub async fn open_project_transaction(
 4453        this: &WeakEntity<Editor>,
 4454        workspace: WeakEntity<Workspace>,
 4455        transaction: ProjectTransaction,
 4456        title: String,
 4457        mut cx: AsyncWindowContext,
 4458    ) -> Result<()> {
 4459        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 4460        cx.update(|_, cx| {
 4461            entries.sort_unstable_by_key(|(buffer, _)| {
 4462                buffer.read(cx).file().map(|f| f.path().clone())
 4463            });
 4464        })?;
 4465
 4466        // If the project transaction's edits are all contained within this editor, then
 4467        // avoid opening a new editor to display them.
 4468
 4469        if let Some((buffer, transaction)) = entries.first() {
 4470            if entries.len() == 1 {
 4471                let excerpt = this.update(&mut cx, |editor, cx| {
 4472                    editor
 4473                        .buffer()
 4474                        .read(cx)
 4475                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 4476                })?;
 4477                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 4478                    if excerpted_buffer == *buffer {
 4479                        let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
 4480                            let excerpt_range = excerpt_range.to_offset(buffer);
 4481                            buffer
 4482                                .edited_ranges_for_transaction::<usize>(transaction)
 4483                                .all(|range| {
 4484                                    excerpt_range.start <= range.start
 4485                                        && excerpt_range.end >= range.end
 4486                                })
 4487                        })?;
 4488
 4489                        if all_edits_within_excerpt {
 4490                            return Ok(());
 4491                        }
 4492                    }
 4493                }
 4494            }
 4495        } else {
 4496            return Ok(());
 4497        }
 4498
 4499        let mut ranges_to_highlight = Vec::new();
 4500        let excerpt_buffer = cx.new(|cx| {
 4501            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 4502            for (buffer_handle, transaction) in &entries {
 4503                let buffer = buffer_handle.read(cx);
 4504                ranges_to_highlight.extend(
 4505                    multibuffer.push_excerpts_with_context_lines(
 4506                        buffer_handle.clone(),
 4507                        buffer
 4508                            .edited_ranges_for_transaction::<usize>(transaction)
 4509                            .collect(),
 4510                        DEFAULT_MULTIBUFFER_CONTEXT,
 4511                        cx,
 4512                    ),
 4513                );
 4514            }
 4515            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 4516            multibuffer
 4517        })?;
 4518
 4519        workspace.update_in(&mut cx, |workspace, window, cx| {
 4520            let project = workspace.project().clone();
 4521            let editor = cx
 4522                .new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), true, window, cx));
 4523            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 4524            editor.update(cx, |editor, cx| {
 4525                editor.highlight_background::<Self>(
 4526                    &ranges_to_highlight,
 4527                    |theme| theme.editor_highlighted_line_background,
 4528                    cx,
 4529                );
 4530            });
 4531        })?;
 4532
 4533        Ok(())
 4534    }
 4535
 4536    pub fn clear_code_action_providers(&mut self) {
 4537        self.code_action_providers.clear();
 4538        self.available_code_actions.take();
 4539    }
 4540
 4541    pub fn add_code_action_provider(
 4542        &mut self,
 4543        provider: Rc<dyn CodeActionProvider>,
 4544        window: &mut Window,
 4545        cx: &mut Context<Self>,
 4546    ) {
 4547        if self
 4548            .code_action_providers
 4549            .iter()
 4550            .any(|existing_provider| existing_provider.id() == provider.id())
 4551        {
 4552            return;
 4553        }
 4554
 4555        self.code_action_providers.push(provider);
 4556        self.refresh_code_actions(window, cx);
 4557    }
 4558
 4559    pub fn remove_code_action_provider(
 4560        &mut self,
 4561        id: Arc<str>,
 4562        window: &mut Window,
 4563        cx: &mut Context<Self>,
 4564    ) {
 4565        self.code_action_providers
 4566            .retain(|provider| provider.id() != id);
 4567        self.refresh_code_actions(window, cx);
 4568    }
 4569
 4570    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 4571        let buffer = self.buffer.read(cx);
 4572        let newest_selection = self.selections.newest_anchor().clone();
 4573        if newest_selection.head().diff_base_anchor.is_some() {
 4574            return None;
 4575        }
 4576        let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
 4577        let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
 4578        if start_buffer != end_buffer {
 4579            return None;
 4580        }
 4581
 4582        self.code_actions_task = Some(cx.spawn_in(window, |this, mut cx| async move {
 4583            cx.background_executor()
 4584                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 4585                .await;
 4586
 4587            let (providers, tasks) = this.update_in(&mut cx, |this, window, cx| {
 4588                let providers = this.code_action_providers.clone();
 4589                let tasks = this
 4590                    .code_action_providers
 4591                    .iter()
 4592                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 4593                    .collect::<Vec<_>>();
 4594                (providers, tasks)
 4595            })?;
 4596
 4597            let mut actions = Vec::new();
 4598            for (provider, provider_actions) in
 4599                providers.into_iter().zip(future::join_all(tasks).await)
 4600            {
 4601                if let Some(provider_actions) = provider_actions.log_err() {
 4602                    actions.extend(provider_actions.into_iter().map(|action| {
 4603                        AvailableCodeAction {
 4604                            excerpt_id: newest_selection.start.excerpt_id,
 4605                            action,
 4606                            provider: provider.clone(),
 4607                        }
 4608                    }));
 4609                }
 4610            }
 4611
 4612            this.update(&mut cx, |this, cx| {
 4613                this.available_code_actions = if actions.is_empty() {
 4614                    None
 4615                } else {
 4616                    Some((
 4617                        Location {
 4618                            buffer: start_buffer,
 4619                            range: start..end,
 4620                        },
 4621                        actions.into(),
 4622                    ))
 4623                };
 4624                cx.notify();
 4625            })
 4626        }));
 4627        None
 4628    }
 4629
 4630    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4631        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 4632            self.show_git_blame_inline = false;
 4633
 4634            self.show_git_blame_inline_delay_task =
 4635                Some(cx.spawn_in(window, |this, mut cx| async move {
 4636                    cx.background_executor().timer(delay).await;
 4637
 4638                    this.update(&mut cx, |this, cx| {
 4639                        this.show_git_blame_inline = true;
 4640                        cx.notify();
 4641                    })
 4642                    .log_err();
 4643                }));
 4644        }
 4645    }
 4646
 4647    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 4648        if self.pending_rename.is_some() {
 4649            return None;
 4650        }
 4651
 4652        let provider = self.semantics_provider.clone()?;
 4653        let buffer = self.buffer.read(cx);
 4654        let newest_selection = self.selections.newest_anchor().clone();
 4655        let cursor_position = newest_selection.head();
 4656        let (cursor_buffer, cursor_buffer_position) =
 4657            buffer.text_anchor_for_position(cursor_position, cx)?;
 4658        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 4659        if cursor_buffer != tail_buffer {
 4660            return None;
 4661        }
 4662        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 4663        self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move {
 4664            cx.background_executor()
 4665                .timer(Duration::from_millis(debounce))
 4666                .await;
 4667
 4668            let highlights = if let Some(highlights) = cx
 4669                .update(|cx| {
 4670                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 4671                })
 4672                .ok()
 4673                .flatten()
 4674            {
 4675                highlights.await.log_err()
 4676            } else {
 4677                None
 4678            };
 4679
 4680            if let Some(highlights) = highlights {
 4681                this.update(&mut cx, |this, cx| {
 4682                    if this.pending_rename.is_some() {
 4683                        return;
 4684                    }
 4685
 4686                    let buffer_id = cursor_position.buffer_id;
 4687                    let buffer = this.buffer.read(cx);
 4688                    if !buffer
 4689                        .text_anchor_for_position(cursor_position, cx)
 4690                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 4691                    {
 4692                        return;
 4693                    }
 4694
 4695                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 4696                    let mut write_ranges = Vec::new();
 4697                    let mut read_ranges = Vec::new();
 4698                    for highlight in highlights {
 4699                        for (excerpt_id, excerpt_range) in
 4700                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 4701                        {
 4702                            let start = highlight
 4703                                .range
 4704                                .start
 4705                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 4706                            let end = highlight
 4707                                .range
 4708                                .end
 4709                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 4710                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 4711                                continue;
 4712                            }
 4713
 4714                            let range = Anchor {
 4715                                buffer_id,
 4716                                excerpt_id,
 4717                                text_anchor: start,
 4718                                diff_base_anchor: None,
 4719                            }..Anchor {
 4720                                buffer_id,
 4721                                excerpt_id,
 4722                                text_anchor: end,
 4723                                diff_base_anchor: None,
 4724                            };
 4725                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 4726                                write_ranges.push(range);
 4727                            } else {
 4728                                read_ranges.push(range);
 4729                            }
 4730                        }
 4731                    }
 4732
 4733                    this.highlight_background::<DocumentHighlightRead>(
 4734                        &read_ranges,
 4735                        |theme| theme.editor_document_highlight_read_background,
 4736                        cx,
 4737                    );
 4738                    this.highlight_background::<DocumentHighlightWrite>(
 4739                        &write_ranges,
 4740                        |theme| theme.editor_document_highlight_write_background,
 4741                        cx,
 4742                    );
 4743                    cx.notify();
 4744                })
 4745                .log_err();
 4746            }
 4747        }));
 4748        None
 4749    }
 4750
 4751    pub fn refresh_selected_text_highlights(
 4752        &mut self,
 4753        window: &mut Window,
 4754        cx: &mut Context<Editor>,
 4755    ) {
 4756        self.selection_highlight_task.take();
 4757        if !EditorSettings::get_global(cx).selection_highlight {
 4758            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 4759            return;
 4760        }
 4761        if self.selections.count() != 1 || self.selections.line_mode {
 4762            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 4763            return;
 4764        }
 4765        let selection = self.selections.newest::<Point>(cx);
 4766        if selection.is_empty() || selection.start.row != selection.end.row {
 4767            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 4768            return;
 4769        }
 4770        let debounce = EditorSettings::get_global(cx).selection_highlight_debounce;
 4771        self.selection_highlight_task = Some(cx.spawn_in(window, |editor, mut cx| async move {
 4772            cx.background_executor()
 4773                .timer(Duration::from_millis(debounce))
 4774                .await;
 4775            let Some(Some(matches_task)) = editor
 4776                .update_in(&mut cx, |editor, _, cx| {
 4777                    if editor.selections.count() != 1 || editor.selections.line_mode {
 4778                        editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 4779                        return None;
 4780                    }
 4781                    let selection = editor.selections.newest::<Point>(cx);
 4782                    if selection.is_empty() || selection.start.row != selection.end.row {
 4783                        editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 4784                        return None;
 4785                    }
 4786                    let buffer = editor.buffer().read(cx).snapshot(cx);
 4787                    let query = buffer.text_for_range(selection.range()).collect::<String>();
 4788                    if query.trim().is_empty() {
 4789                        editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 4790                        return None;
 4791                    }
 4792                    Some(cx.background_spawn(async move {
 4793                        let mut ranges = Vec::new();
 4794                        let selection_anchors = selection.range().to_anchors(&buffer);
 4795                        for range in [buffer.anchor_before(0)..buffer.anchor_after(buffer.len())] {
 4796                            for (search_buffer, search_range, excerpt_id) in
 4797                                buffer.range_to_buffer_ranges(range)
 4798                            {
 4799                                ranges.extend(
 4800                                    project::search::SearchQuery::text(
 4801                                        query.clone(),
 4802                                        false,
 4803                                        false,
 4804                                        false,
 4805                                        Default::default(),
 4806                                        Default::default(),
 4807                                        None,
 4808                                    )
 4809                                    .unwrap()
 4810                                    .search(search_buffer, Some(search_range.clone()))
 4811                                    .await
 4812                                    .into_iter()
 4813                                    .filter_map(
 4814                                        |match_range| {
 4815                                            let start = search_buffer.anchor_after(
 4816                                                search_range.start + match_range.start,
 4817                                            );
 4818                                            let end = search_buffer.anchor_before(
 4819                                                search_range.start + match_range.end,
 4820                                            );
 4821                                            let range = Anchor::range_in_buffer(
 4822                                                excerpt_id,
 4823                                                search_buffer.remote_id(),
 4824                                                start..end,
 4825                                            );
 4826                                            (range != selection_anchors).then_some(range)
 4827                                        },
 4828                                    ),
 4829                                );
 4830                            }
 4831                        }
 4832                        ranges
 4833                    }))
 4834                })
 4835                .log_err()
 4836            else {
 4837                return;
 4838            };
 4839            let matches = matches_task.await;
 4840            editor
 4841                .update_in(&mut cx, |editor, _, cx| {
 4842                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 4843                    if !matches.is_empty() {
 4844                        editor.highlight_background::<SelectedTextHighlight>(
 4845                            &matches,
 4846                            |theme| theme.editor_document_highlight_bracket_background,
 4847                            cx,
 4848                        )
 4849                    }
 4850                })
 4851                .log_err();
 4852        }));
 4853    }
 4854
 4855    pub fn refresh_inline_completion(
 4856        &mut self,
 4857        debounce: bool,
 4858        user_requested: bool,
 4859        window: &mut Window,
 4860        cx: &mut Context<Self>,
 4861    ) -> Option<()> {
 4862        let provider = self.edit_prediction_provider()?;
 4863        let cursor = self.selections.newest_anchor().head();
 4864        let (buffer, cursor_buffer_position) =
 4865            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 4866
 4867        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 4868            self.discard_inline_completion(false, cx);
 4869            return None;
 4870        }
 4871
 4872        if !user_requested
 4873            && (!self.should_show_edit_predictions()
 4874                || !self.is_focused(window)
 4875                || buffer.read(cx).is_empty())
 4876        {
 4877            self.discard_inline_completion(false, cx);
 4878            return None;
 4879        }
 4880
 4881        self.update_visible_inline_completion(window, cx);
 4882        provider.refresh(
 4883            self.project.clone(),
 4884            buffer,
 4885            cursor_buffer_position,
 4886            debounce,
 4887            cx,
 4888        );
 4889        Some(())
 4890    }
 4891
 4892    fn show_edit_predictions_in_menu(&self) -> bool {
 4893        match self.edit_prediction_settings {
 4894            EditPredictionSettings::Disabled => false,
 4895            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 4896        }
 4897    }
 4898
 4899    pub fn edit_predictions_enabled(&self) -> bool {
 4900        match self.edit_prediction_settings {
 4901            EditPredictionSettings::Disabled => false,
 4902            EditPredictionSettings::Enabled { .. } => true,
 4903        }
 4904    }
 4905
 4906    fn edit_prediction_requires_modifier(&self) -> bool {
 4907        match self.edit_prediction_settings {
 4908            EditPredictionSettings::Disabled => false,
 4909            EditPredictionSettings::Enabled {
 4910                preview_requires_modifier,
 4911                ..
 4912            } => preview_requires_modifier,
 4913        }
 4914    }
 4915
 4916    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 4917        if self.edit_prediction_provider.is_none() {
 4918            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 4919        } else {
 4920            let selection = self.selections.newest_anchor();
 4921            let cursor = selection.head();
 4922
 4923            if let Some((buffer, cursor_buffer_position)) =
 4924                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 4925            {
 4926                self.edit_prediction_settings =
 4927                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 4928            }
 4929        }
 4930    }
 4931
 4932    fn edit_prediction_settings_at_position(
 4933        &self,
 4934        buffer: &Entity<Buffer>,
 4935        buffer_position: language::Anchor,
 4936        cx: &App,
 4937    ) -> EditPredictionSettings {
 4938        if self.mode != EditorMode::Full
 4939            || !self.show_inline_completions_override.unwrap_or(true)
 4940            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 4941        {
 4942            return EditPredictionSettings::Disabled;
 4943        }
 4944
 4945        let buffer = buffer.read(cx);
 4946
 4947        let file = buffer.file();
 4948
 4949        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 4950            return EditPredictionSettings::Disabled;
 4951        };
 4952
 4953        let by_provider = matches!(
 4954            self.menu_inline_completions_policy,
 4955            MenuInlineCompletionsPolicy::ByProvider
 4956        );
 4957
 4958        let show_in_menu = by_provider
 4959            && self
 4960                .edit_prediction_provider
 4961                .as_ref()
 4962                .map_or(false, |provider| {
 4963                    provider.provider.show_completions_in_menu()
 4964                });
 4965
 4966        let preview_requires_modifier =
 4967            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 4968
 4969        EditPredictionSettings::Enabled {
 4970            show_in_menu,
 4971            preview_requires_modifier,
 4972        }
 4973    }
 4974
 4975    fn should_show_edit_predictions(&self) -> bool {
 4976        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 4977    }
 4978
 4979    pub fn edit_prediction_preview_is_active(&self) -> bool {
 4980        matches!(
 4981            self.edit_prediction_preview,
 4982            EditPredictionPreview::Active { .. }
 4983        )
 4984    }
 4985
 4986    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 4987        let cursor = self.selections.newest_anchor().head();
 4988        if let Some((buffer, cursor_position)) =
 4989            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 4990        {
 4991            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 4992        } else {
 4993            false
 4994        }
 4995    }
 4996
 4997    fn edit_predictions_enabled_in_buffer(
 4998        &self,
 4999        buffer: &Entity<Buffer>,
 5000        buffer_position: language::Anchor,
 5001        cx: &App,
 5002    ) -> bool {
 5003        maybe!({
 5004            let provider = self.edit_prediction_provider()?;
 5005            if !provider.is_enabled(&buffer, buffer_position, cx) {
 5006                return Some(false);
 5007            }
 5008            let buffer = buffer.read(cx);
 5009            let Some(file) = buffer.file() else {
 5010                return Some(true);
 5011            };
 5012            let settings = all_language_settings(Some(file), cx);
 5013            Some(settings.inline_completions_enabled_for_path(file.path()))
 5014        })
 5015        .unwrap_or(false)
 5016    }
 5017
 5018    fn cycle_inline_completion(
 5019        &mut self,
 5020        direction: Direction,
 5021        window: &mut Window,
 5022        cx: &mut Context<Self>,
 5023    ) -> Option<()> {
 5024        let provider = self.edit_prediction_provider()?;
 5025        let cursor = self.selections.newest_anchor().head();
 5026        let (buffer, cursor_buffer_position) =
 5027            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 5028        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 5029            return None;
 5030        }
 5031
 5032        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 5033        self.update_visible_inline_completion(window, cx);
 5034
 5035        Some(())
 5036    }
 5037
 5038    pub fn show_inline_completion(
 5039        &mut self,
 5040        _: &ShowEditPrediction,
 5041        window: &mut Window,
 5042        cx: &mut Context<Self>,
 5043    ) {
 5044        if !self.has_active_inline_completion() {
 5045            self.refresh_inline_completion(false, true, window, cx);
 5046            return;
 5047        }
 5048
 5049        self.update_visible_inline_completion(window, cx);
 5050    }
 5051
 5052    pub fn display_cursor_names(
 5053        &mut self,
 5054        _: &DisplayCursorNames,
 5055        window: &mut Window,
 5056        cx: &mut Context<Self>,
 5057    ) {
 5058        self.show_cursor_names(window, cx);
 5059    }
 5060
 5061    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5062        self.show_cursor_names = true;
 5063        cx.notify();
 5064        cx.spawn_in(window, |this, mut cx| async move {
 5065            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 5066            this.update(&mut cx, |this, cx| {
 5067                this.show_cursor_names = false;
 5068                cx.notify()
 5069            })
 5070            .ok()
 5071        })
 5072        .detach();
 5073    }
 5074
 5075    pub fn next_edit_prediction(
 5076        &mut self,
 5077        _: &NextEditPrediction,
 5078        window: &mut Window,
 5079        cx: &mut Context<Self>,
 5080    ) {
 5081        if self.has_active_inline_completion() {
 5082            self.cycle_inline_completion(Direction::Next, window, cx);
 5083        } else {
 5084            let is_copilot_disabled = self
 5085                .refresh_inline_completion(false, true, window, cx)
 5086                .is_none();
 5087            if is_copilot_disabled {
 5088                cx.propagate();
 5089            }
 5090        }
 5091    }
 5092
 5093    pub fn previous_edit_prediction(
 5094        &mut self,
 5095        _: &PreviousEditPrediction,
 5096        window: &mut Window,
 5097        cx: &mut Context<Self>,
 5098    ) {
 5099        if self.has_active_inline_completion() {
 5100            self.cycle_inline_completion(Direction::Prev, window, cx);
 5101        } else {
 5102            let is_copilot_disabled = self
 5103                .refresh_inline_completion(false, true, window, cx)
 5104                .is_none();
 5105            if is_copilot_disabled {
 5106                cx.propagate();
 5107            }
 5108        }
 5109    }
 5110
 5111    pub fn accept_edit_prediction(
 5112        &mut self,
 5113        _: &AcceptEditPrediction,
 5114        window: &mut Window,
 5115        cx: &mut Context<Self>,
 5116    ) {
 5117        if self.show_edit_predictions_in_menu() {
 5118            self.hide_context_menu(window, cx);
 5119        }
 5120
 5121        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 5122            return;
 5123        };
 5124
 5125        self.report_inline_completion_event(
 5126            active_inline_completion.completion_id.clone(),
 5127            true,
 5128            cx,
 5129        );
 5130
 5131        match &active_inline_completion.completion {
 5132            InlineCompletion::Move { target, .. } => {
 5133                let target = *target;
 5134
 5135                if let Some(position_map) = &self.last_position_map {
 5136                    if position_map
 5137                        .visible_row_range
 5138                        .contains(&target.to_display_point(&position_map.snapshot).row())
 5139                        || !self.edit_prediction_requires_modifier()
 5140                    {
 5141                        self.unfold_ranges(&[target..target], true, false, cx);
 5142                        // Note that this is also done in vim's handler of the Tab action.
 5143                        self.change_selections(
 5144                            Some(Autoscroll::newest()),
 5145                            window,
 5146                            cx,
 5147                            |selections| {
 5148                                selections.select_anchor_ranges([target..target]);
 5149                            },
 5150                        );
 5151                        self.clear_row_highlights::<EditPredictionPreview>();
 5152
 5153                        self.edit_prediction_preview
 5154                            .set_previous_scroll_position(None);
 5155                    } else {
 5156                        self.edit_prediction_preview
 5157                            .set_previous_scroll_position(Some(
 5158                                position_map.snapshot.scroll_anchor,
 5159                            ));
 5160
 5161                        self.highlight_rows::<EditPredictionPreview>(
 5162                            target..target,
 5163                            cx.theme().colors().editor_highlighted_line_background,
 5164                            true,
 5165                            cx,
 5166                        );
 5167                        self.request_autoscroll(Autoscroll::fit(), cx);
 5168                    }
 5169                }
 5170            }
 5171            InlineCompletion::Edit { edits, .. } => {
 5172                if let Some(provider) = self.edit_prediction_provider() {
 5173                    provider.accept(cx);
 5174                }
 5175
 5176                let snapshot = self.buffer.read(cx).snapshot(cx);
 5177                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 5178
 5179                self.buffer.update(cx, |buffer, cx| {
 5180                    buffer.edit(edits.iter().cloned(), None, cx)
 5181                });
 5182
 5183                self.change_selections(None, window, cx, |s| {
 5184                    s.select_anchor_ranges([last_edit_end..last_edit_end])
 5185                });
 5186
 5187                self.update_visible_inline_completion(window, cx);
 5188                if self.active_inline_completion.is_none() {
 5189                    self.refresh_inline_completion(true, true, window, cx);
 5190                }
 5191
 5192                cx.notify();
 5193            }
 5194        }
 5195
 5196        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 5197    }
 5198
 5199    pub fn accept_partial_inline_completion(
 5200        &mut self,
 5201        _: &AcceptPartialEditPrediction,
 5202        window: &mut Window,
 5203        cx: &mut Context<Self>,
 5204    ) {
 5205        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 5206            return;
 5207        };
 5208        if self.selections.count() != 1 {
 5209            return;
 5210        }
 5211
 5212        self.report_inline_completion_event(
 5213            active_inline_completion.completion_id.clone(),
 5214            true,
 5215            cx,
 5216        );
 5217
 5218        match &active_inline_completion.completion {
 5219            InlineCompletion::Move { target, .. } => {
 5220                let target = *target;
 5221                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 5222                    selections.select_anchor_ranges([target..target]);
 5223                });
 5224            }
 5225            InlineCompletion::Edit { edits, .. } => {
 5226                // Find an insertion that starts at the cursor position.
 5227                let snapshot = self.buffer.read(cx).snapshot(cx);
 5228                let cursor_offset = self.selections.newest::<usize>(cx).head();
 5229                let insertion = edits.iter().find_map(|(range, text)| {
 5230                    let range = range.to_offset(&snapshot);
 5231                    if range.is_empty() && range.start == cursor_offset {
 5232                        Some(text)
 5233                    } else {
 5234                        None
 5235                    }
 5236                });
 5237
 5238                if let Some(text) = insertion {
 5239                    let mut partial_completion = text
 5240                        .chars()
 5241                        .by_ref()
 5242                        .take_while(|c| c.is_alphabetic())
 5243                        .collect::<String>();
 5244                    if partial_completion.is_empty() {
 5245                        partial_completion = text
 5246                            .chars()
 5247                            .by_ref()
 5248                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 5249                            .collect::<String>();
 5250                    }
 5251
 5252                    cx.emit(EditorEvent::InputHandled {
 5253                        utf16_range_to_replace: None,
 5254                        text: partial_completion.clone().into(),
 5255                    });
 5256
 5257                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 5258
 5259                    self.refresh_inline_completion(true, true, window, cx);
 5260                    cx.notify();
 5261                } else {
 5262                    self.accept_edit_prediction(&Default::default(), window, cx);
 5263                }
 5264            }
 5265        }
 5266    }
 5267
 5268    fn discard_inline_completion(
 5269        &mut self,
 5270        should_report_inline_completion_event: bool,
 5271        cx: &mut Context<Self>,
 5272    ) -> bool {
 5273        if should_report_inline_completion_event {
 5274            let completion_id = self
 5275                .active_inline_completion
 5276                .as_ref()
 5277                .and_then(|active_completion| active_completion.completion_id.clone());
 5278
 5279            self.report_inline_completion_event(completion_id, false, cx);
 5280        }
 5281
 5282        if let Some(provider) = self.edit_prediction_provider() {
 5283            provider.discard(cx);
 5284        }
 5285
 5286        self.take_active_inline_completion(cx)
 5287    }
 5288
 5289    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 5290        let Some(provider) = self.edit_prediction_provider() else {
 5291            return;
 5292        };
 5293
 5294        let Some((_, buffer, _)) = self
 5295            .buffer
 5296            .read(cx)
 5297            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 5298        else {
 5299            return;
 5300        };
 5301
 5302        let extension = buffer
 5303            .read(cx)
 5304            .file()
 5305            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 5306
 5307        let event_type = match accepted {
 5308            true => "Edit Prediction Accepted",
 5309            false => "Edit Prediction Discarded",
 5310        };
 5311        telemetry::event!(
 5312            event_type,
 5313            provider = provider.name(),
 5314            prediction_id = id,
 5315            suggestion_accepted = accepted,
 5316            file_extension = extension,
 5317        );
 5318    }
 5319
 5320    pub fn has_active_inline_completion(&self) -> bool {
 5321        self.active_inline_completion.is_some()
 5322    }
 5323
 5324    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 5325        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 5326            return false;
 5327        };
 5328
 5329        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 5330        self.clear_highlights::<InlineCompletionHighlight>(cx);
 5331        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 5332        true
 5333    }
 5334
 5335    /// Returns true when we're displaying the edit prediction popover below the cursor
 5336    /// like we are not previewing and the LSP autocomplete menu is visible
 5337    /// or we are in `when_holding_modifier` mode.
 5338    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 5339        if self.edit_prediction_preview_is_active()
 5340            || !self.show_edit_predictions_in_menu()
 5341            || !self.edit_predictions_enabled()
 5342        {
 5343            return false;
 5344        }
 5345
 5346        if self.has_visible_completions_menu() {
 5347            return true;
 5348        }
 5349
 5350        has_completion && self.edit_prediction_requires_modifier()
 5351    }
 5352
 5353    fn handle_modifiers_changed(
 5354        &mut self,
 5355        modifiers: Modifiers,
 5356        position_map: &PositionMap,
 5357        window: &mut Window,
 5358        cx: &mut Context<Self>,
 5359    ) {
 5360        if self.show_edit_predictions_in_menu() {
 5361            self.update_edit_prediction_preview(&modifiers, window, cx);
 5362        }
 5363
 5364        self.update_selection_mode(&modifiers, position_map, window, cx);
 5365
 5366        let mouse_position = window.mouse_position();
 5367        if !position_map.text_hitbox.is_hovered(window) {
 5368            return;
 5369        }
 5370
 5371        self.update_hovered_link(
 5372            position_map.point_for_position(mouse_position),
 5373            &position_map.snapshot,
 5374            modifiers,
 5375            window,
 5376            cx,
 5377        )
 5378    }
 5379
 5380    fn update_selection_mode(
 5381        &mut self,
 5382        modifiers: &Modifiers,
 5383        position_map: &PositionMap,
 5384        window: &mut Window,
 5385        cx: &mut Context<Self>,
 5386    ) {
 5387        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 5388            return;
 5389        }
 5390
 5391        let mouse_position = window.mouse_position();
 5392        let point_for_position = position_map.point_for_position(mouse_position);
 5393        let position = point_for_position.previous_valid;
 5394
 5395        self.select(
 5396            SelectPhase::BeginColumnar {
 5397                position,
 5398                reset: false,
 5399                goal_column: point_for_position.exact_unclipped.column(),
 5400            },
 5401            window,
 5402            cx,
 5403        );
 5404    }
 5405
 5406    fn update_edit_prediction_preview(
 5407        &mut self,
 5408        modifiers: &Modifiers,
 5409        window: &mut Window,
 5410        cx: &mut Context<Self>,
 5411    ) {
 5412        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 5413        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 5414            return;
 5415        };
 5416
 5417        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 5418            if matches!(
 5419                self.edit_prediction_preview,
 5420                EditPredictionPreview::Inactive { .. }
 5421            ) {
 5422                self.edit_prediction_preview = EditPredictionPreview::Active {
 5423                    previous_scroll_position: None,
 5424                    since: Instant::now(),
 5425                };
 5426
 5427                self.update_visible_inline_completion(window, cx);
 5428                cx.notify();
 5429            }
 5430        } else if let EditPredictionPreview::Active {
 5431            previous_scroll_position,
 5432            since,
 5433        } = self.edit_prediction_preview
 5434        {
 5435            if let (Some(previous_scroll_position), Some(position_map)) =
 5436                (previous_scroll_position, self.last_position_map.as_ref())
 5437            {
 5438                self.set_scroll_position(
 5439                    previous_scroll_position
 5440                        .scroll_position(&position_map.snapshot.display_snapshot),
 5441                    window,
 5442                    cx,
 5443                );
 5444            }
 5445
 5446            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 5447                released_too_fast: since.elapsed() < Duration::from_millis(200),
 5448            };
 5449            self.clear_row_highlights::<EditPredictionPreview>();
 5450            self.update_visible_inline_completion(window, cx);
 5451            cx.notify();
 5452        }
 5453    }
 5454
 5455    fn update_visible_inline_completion(
 5456        &mut self,
 5457        _window: &mut Window,
 5458        cx: &mut Context<Self>,
 5459    ) -> Option<()> {
 5460        let selection = self.selections.newest_anchor();
 5461        let cursor = selection.head();
 5462        let multibuffer = self.buffer.read(cx).snapshot(cx);
 5463        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 5464        let excerpt_id = cursor.excerpt_id;
 5465
 5466        let show_in_menu = self.show_edit_predictions_in_menu();
 5467        let completions_menu_has_precedence = !show_in_menu
 5468            && (self.context_menu.borrow().is_some()
 5469                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 5470
 5471        if completions_menu_has_precedence
 5472            || !offset_selection.is_empty()
 5473            || self
 5474                .active_inline_completion
 5475                .as_ref()
 5476                .map_or(false, |completion| {
 5477                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 5478                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 5479                    !invalidation_range.contains(&offset_selection.head())
 5480                })
 5481        {
 5482            self.discard_inline_completion(false, cx);
 5483            return None;
 5484        }
 5485
 5486        self.take_active_inline_completion(cx);
 5487        let Some(provider) = self.edit_prediction_provider() else {
 5488            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 5489            return None;
 5490        };
 5491
 5492        let (buffer, cursor_buffer_position) =
 5493            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 5494
 5495        self.edit_prediction_settings =
 5496            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 5497
 5498        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 5499
 5500        if self.edit_prediction_indent_conflict {
 5501            let cursor_point = cursor.to_point(&multibuffer);
 5502
 5503            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 5504
 5505            if let Some((_, indent)) = indents.iter().next() {
 5506                if indent.len == cursor_point.column {
 5507                    self.edit_prediction_indent_conflict = false;
 5508                }
 5509            }
 5510        }
 5511
 5512        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 5513        let edits = inline_completion
 5514            .edits
 5515            .into_iter()
 5516            .flat_map(|(range, new_text)| {
 5517                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 5518                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 5519                Some((start..end, new_text))
 5520            })
 5521            .collect::<Vec<_>>();
 5522        if edits.is_empty() {
 5523            return None;
 5524        }
 5525
 5526        let first_edit_start = edits.first().unwrap().0.start;
 5527        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 5528        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 5529
 5530        let last_edit_end = edits.last().unwrap().0.end;
 5531        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 5532        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 5533
 5534        let cursor_row = cursor.to_point(&multibuffer).row;
 5535
 5536        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 5537
 5538        let mut inlay_ids = Vec::new();
 5539        let invalidation_row_range;
 5540        let move_invalidation_row_range = if cursor_row < edit_start_row {
 5541            Some(cursor_row..edit_end_row)
 5542        } else if cursor_row > edit_end_row {
 5543            Some(edit_start_row..cursor_row)
 5544        } else {
 5545            None
 5546        };
 5547        let is_move =
 5548            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 5549        let completion = if is_move {
 5550            invalidation_row_range =
 5551                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 5552            let target = first_edit_start;
 5553            InlineCompletion::Move { target, snapshot }
 5554        } else {
 5555            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 5556                && !self.inline_completions_hidden_for_vim_mode;
 5557
 5558            if show_completions_in_buffer {
 5559                if edits
 5560                    .iter()
 5561                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 5562                {
 5563                    let mut inlays = Vec::new();
 5564                    for (range, new_text) in &edits {
 5565                        let inlay = Inlay::inline_completion(
 5566                            post_inc(&mut self.next_inlay_id),
 5567                            range.start,
 5568                            new_text.as_str(),
 5569                        );
 5570                        inlay_ids.push(inlay.id);
 5571                        inlays.push(inlay);
 5572                    }
 5573
 5574                    self.splice_inlays(&[], inlays, cx);
 5575                } else {
 5576                    let background_color = cx.theme().status().deleted_background;
 5577                    self.highlight_text::<InlineCompletionHighlight>(
 5578                        edits.iter().map(|(range, _)| range.clone()).collect(),
 5579                        HighlightStyle {
 5580                            background_color: Some(background_color),
 5581                            ..Default::default()
 5582                        },
 5583                        cx,
 5584                    );
 5585                }
 5586            }
 5587
 5588            invalidation_row_range = edit_start_row..edit_end_row;
 5589
 5590            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 5591                if provider.show_tab_accept_marker() {
 5592                    EditDisplayMode::TabAccept
 5593                } else {
 5594                    EditDisplayMode::Inline
 5595                }
 5596            } else {
 5597                EditDisplayMode::DiffPopover
 5598            };
 5599
 5600            InlineCompletion::Edit {
 5601                edits,
 5602                edit_preview: inline_completion.edit_preview,
 5603                display_mode,
 5604                snapshot,
 5605            }
 5606        };
 5607
 5608        let invalidation_range = multibuffer
 5609            .anchor_before(Point::new(invalidation_row_range.start, 0))
 5610            ..multibuffer.anchor_after(Point::new(
 5611                invalidation_row_range.end,
 5612                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 5613            ));
 5614
 5615        self.stale_inline_completion_in_menu = None;
 5616        self.active_inline_completion = Some(InlineCompletionState {
 5617            inlay_ids,
 5618            completion,
 5619            completion_id: inline_completion.id,
 5620            invalidation_range,
 5621        });
 5622
 5623        cx.notify();
 5624
 5625        Some(())
 5626    }
 5627
 5628    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 5629        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 5630    }
 5631
 5632    fn render_code_actions_indicator(
 5633        &self,
 5634        _style: &EditorStyle,
 5635        row: DisplayRow,
 5636        is_active: bool,
 5637        cx: &mut Context<Self>,
 5638    ) -> Option<IconButton> {
 5639        if self.available_code_actions.is_some() {
 5640            Some(
 5641                IconButton::new("code_actions_indicator", ui::IconName::Bolt)
 5642                    .shape(ui::IconButtonShape::Square)
 5643                    .icon_size(IconSize::XSmall)
 5644                    .icon_color(Color::Muted)
 5645                    .toggle_state(is_active)
 5646                    .tooltip({
 5647                        let focus_handle = self.focus_handle.clone();
 5648                        move |window, cx| {
 5649                            Tooltip::for_action_in(
 5650                                "Toggle Code Actions",
 5651                                &ToggleCodeActions {
 5652                                    deployed_from_indicator: None,
 5653                                },
 5654                                &focus_handle,
 5655                                window,
 5656                                cx,
 5657                            )
 5658                        }
 5659                    })
 5660                    .on_click(cx.listener(move |editor, _e, window, cx| {
 5661                        window.focus(&editor.focus_handle(cx));
 5662                        editor.toggle_code_actions(
 5663                            &ToggleCodeActions {
 5664                                deployed_from_indicator: Some(row),
 5665                            },
 5666                            window,
 5667                            cx,
 5668                        );
 5669                    })),
 5670            )
 5671        } else {
 5672            None
 5673        }
 5674    }
 5675
 5676    fn clear_tasks(&mut self) {
 5677        self.tasks.clear()
 5678    }
 5679
 5680    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 5681        if self.tasks.insert(key, value).is_some() {
 5682            // This case should hopefully be rare, but just in case...
 5683            log::error!("multiple different run targets found on a single line, only the last target will be rendered")
 5684        }
 5685    }
 5686
 5687    fn build_tasks_context(
 5688        project: &Entity<Project>,
 5689        buffer: &Entity<Buffer>,
 5690        buffer_row: u32,
 5691        tasks: &Arc<RunnableTasks>,
 5692        cx: &mut Context<Self>,
 5693    ) -> Task<Option<task::TaskContext>> {
 5694        let position = Point::new(buffer_row, tasks.column);
 5695        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 5696        let location = Location {
 5697            buffer: buffer.clone(),
 5698            range: range_start..range_start,
 5699        };
 5700        // Fill in the environmental variables from the tree-sitter captures
 5701        let mut captured_task_variables = TaskVariables::default();
 5702        for (capture_name, value) in tasks.extra_variables.clone() {
 5703            captured_task_variables.insert(
 5704                task::VariableName::Custom(capture_name.into()),
 5705                value.clone(),
 5706            );
 5707        }
 5708        project.update(cx, |project, cx| {
 5709            project.task_store().update(cx, |task_store, cx| {
 5710                task_store.task_context_for_location(captured_task_variables, location, cx)
 5711            })
 5712        })
 5713    }
 5714
 5715    pub fn spawn_nearest_task(
 5716        &mut self,
 5717        action: &SpawnNearestTask,
 5718        window: &mut Window,
 5719        cx: &mut Context<Self>,
 5720    ) {
 5721        let Some((workspace, _)) = self.workspace.clone() else {
 5722            return;
 5723        };
 5724        let Some(project) = self.project.clone() else {
 5725            return;
 5726        };
 5727
 5728        // Try to find a closest, enclosing node using tree-sitter that has a
 5729        // task
 5730        let Some((buffer, buffer_row, tasks)) = self
 5731            .find_enclosing_node_task(cx)
 5732            // Or find the task that's closest in row-distance.
 5733            .or_else(|| self.find_closest_task(cx))
 5734        else {
 5735            return;
 5736        };
 5737
 5738        let reveal_strategy = action.reveal;
 5739        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5740        cx.spawn_in(window, |_, mut cx| async move {
 5741            let context = task_context.await?;
 5742            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 5743
 5744            let resolved = resolved_task.resolved.as_mut()?;
 5745            resolved.reveal = reveal_strategy;
 5746
 5747            workspace
 5748                .update(&mut cx, |workspace, cx| {
 5749                    workspace::tasks::schedule_resolved_task(
 5750                        workspace,
 5751                        task_source_kind,
 5752                        resolved_task,
 5753                        false,
 5754                        cx,
 5755                    );
 5756                })
 5757                .ok()
 5758        })
 5759        .detach();
 5760    }
 5761
 5762    fn find_closest_task(
 5763        &mut self,
 5764        cx: &mut Context<Self>,
 5765    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 5766        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 5767
 5768        let ((buffer_id, row), tasks) = self
 5769            .tasks
 5770            .iter()
 5771            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 5772
 5773        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 5774        let tasks = Arc::new(tasks.to_owned());
 5775        Some((buffer, *row, tasks))
 5776    }
 5777
 5778    fn find_enclosing_node_task(
 5779        &mut self,
 5780        cx: &mut Context<Self>,
 5781    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 5782        let snapshot = self.buffer.read(cx).snapshot(cx);
 5783        let offset = self.selections.newest::<usize>(cx).head();
 5784        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 5785        let buffer_id = excerpt.buffer().remote_id();
 5786
 5787        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 5788        let mut cursor = layer.node().walk();
 5789
 5790        while cursor.goto_first_child_for_byte(offset).is_some() {
 5791            if cursor.node().end_byte() == offset {
 5792                cursor.goto_next_sibling();
 5793            }
 5794        }
 5795
 5796        // Ascend to the smallest ancestor that contains the range and has a task.
 5797        loop {
 5798            let node = cursor.node();
 5799            let node_range = node.byte_range();
 5800            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 5801
 5802            // Check if this node contains our offset
 5803            if node_range.start <= offset && node_range.end >= offset {
 5804                // If it contains offset, check for task
 5805                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 5806                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 5807                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 5808                }
 5809            }
 5810
 5811            if !cursor.goto_parent() {
 5812                break;
 5813            }
 5814        }
 5815        None
 5816    }
 5817
 5818    fn render_run_indicator(
 5819        &self,
 5820        _style: &EditorStyle,
 5821        is_active: bool,
 5822        row: DisplayRow,
 5823        cx: &mut Context<Self>,
 5824    ) -> IconButton {
 5825        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 5826            .shape(ui::IconButtonShape::Square)
 5827            .icon_size(IconSize::XSmall)
 5828            .icon_color(Color::Muted)
 5829            .toggle_state(is_active)
 5830            .on_click(cx.listener(move |editor, _e, window, cx| {
 5831                window.focus(&editor.focus_handle(cx));
 5832                editor.toggle_code_actions(
 5833                    &ToggleCodeActions {
 5834                        deployed_from_indicator: Some(row),
 5835                    },
 5836                    window,
 5837                    cx,
 5838                );
 5839            }))
 5840    }
 5841
 5842    pub fn context_menu_visible(&self) -> bool {
 5843        !self.edit_prediction_preview_is_active()
 5844            && self
 5845                .context_menu
 5846                .borrow()
 5847                .as_ref()
 5848                .map_or(false, |menu| menu.visible())
 5849    }
 5850
 5851    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 5852        self.context_menu
 5853            .borrow()
 5854            .as_ref()
 5855            .map(|menu| menu.origin())
 5856    }
 5857
 5858    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 5859    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 5860
 5861    #[allow(clippy::too_many_arguments)]
 5862    fn render_edit_prediction_popover(
 5863        &mut self,
 5864        text_bounds: &Bounds<Pixels>,
 5865        content_origin: gpui::Point<Pixels>,
 5866        editor_snapshot: &EditorSnapshot,
 5867        visible_row_range: Range<DisplayRow>,
 5868        scroll_top: f32,
 5869        scroll_bottom: f32,
 5870        line_layouts: &[LineWithInvisibles],
 5871        line_height: Pixels,
 5872        scroll_pixel_position: gpui::Point<Pixels>,
 5873        newest_selection_head: Option<DisplayPoint>,
 5874        editor_width: Pixels,
 5875        style: &EditorStyle,
 5876        window: &mut Window,
 5877        cx: &mut App,
 5878    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 5879        let active_inline_completion = self.active_inline_completion.as_ref()?;
 5880
 5881        if self.edit_prediction_visible_in_cursor_popover(true) {
 5882            return None;
 5883        }
 5884
 5885        match &active_inline_completion.completion {
 5886            InlineCompletion::Move { target, .. } => {
 5887                let target_display_point = target.to_display_point(editor_snapshot);
 5888
 5889                if self.edit_prediction_requires_modifier() {
 5890                    if !self.edit_prediction_preview_is_active() {
 5891                        return None;
 5892                    }
 5893
 5894                    self.render_edit_prediction_modifier_jump_popover(
 5895                        text_bounds,
 5896                        content_origin,
 5897                        visible_row_range,
 5898                        line_layouts,
 5899                        line_height,
 5900                        scroll_pixel_position,
 5901                        newest_selection_head,
 5902                        target_display_point,
 5903                        window,
 5904                        cx,
 5905                    )
 5906                } else {
 5907                    self.render_edit_prediction_eager_jump_popover(
 5908                        text_bounds,
 5909                        content_origin,
 5910                        editor_snapshot,
 5911                        visible_row_range,
 5912                        scroll_top,
 5913                        scroll_bottom,
 5914                        line_height,
 5915                        scroll_pixel_position,
 5916                        target_display_point,
 5917                        editor_width,
 5918                        window,
 5919                        cx,
 5920                    )
 5921                }
 5922            }
 5923            InlineCompletion::Edit {
 5924                display_mode: EditDisplayMode::Inline,
 5925                ..
 5926            } => None,
 5927            InlineCompletion::Edit {
 5928                display_mode: EditDisplayMode::TabAccept,
 5929                edits,
 5930                ..
 5931            } => {
 5932                let range = &edits.first()?.0;
 5933                let target_display_point = range.end.to_display_point(editor_snapshot);
 5934
 5935                self.render_edit_prediction_end_of_line_popover(
 5936                    "Accept",
 5937                    editor_snapshot,
 5938                    visible_row_range,
 5939                    target_display_point,
 5940                    line_height,
 5941                    scroll_pixel_position,
 5942                    content_origin,
 5943                    editor_width,
 5944                    window,
 5945                    cx,
 5946                )
 5947            }
 5948            InlineCompletion::Edit {
 5949                edits,
 5950                edit_preview,
 5951                display_mode: EditDisplayMode::DiffPopover,
 5952                snapshot,
 5953            } => self.render_edit_prediction_diff_popover(
 5954                text_bounds,
 5955                content_origin,
 5956                editor_snapshot,
 5957                visible_row_range,
 5958                line_layouts,
 5959                line_height,
 5960                scroll_pixel_position,
 5961                newest_selection_head,
 5962                editor_width,
 5963                style,
 5964                edits,
 5965                edit_preview,
 5966                snapshot,
 5967                window,
 5968                cx,
 5969            ),
 5970        }
 5971    }
 5972
 5973    #[allow(clippy::too_many_arguments)]
 5974    fn render_edit_prediction_modifier_jump_popover(
 5975        &mut self,
 5976        text_bounds: &Bounds<Pixels>,
 5977        content_origin: gpui::Point<Pixels>,
 5978        visible_row_range: Range<DisplayRow>,
 5979        line_layouts: &[LineWithInvisibles],
 5980        line_height: Pixels,
 5981        scroll_pixel_position: gpui::Point<Pixels>,
 5982        newest_selection_head: Option<DisplayPoint>,
 5983        target_display_point: DisplayPoint,
 5984        window: &mut Window,
 5985        cx: &mut App,
 5986    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 5987        let scrolled_content_origin =
 5988            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 5989
 5990        const SCROLL_PADDING_Y: Pixels = px(12.);
 5991
 5992        if target_display_point.row() < visible_row_range.start {
 5993            return self.render_edit_prediction_scroll_popover(
 5994                |_| SCROLL_PADDING_Y,
 5995                IconName::ArrowUp,
 5996                visible_row_range,
 5997                line_layouts,
 5998                newest_selection_head,
 5999                scrolled_content_origin,
 6000                window,
 6001                cx,
 6002            );
 6003        } else if target_display_point.row() >= visible_row_range.end {
 6004            return self.render_edit_prediction_scroll_popover(
 6005                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 6006                IconName::ArrowDown,
 6007                visible_row_range,
 6008                line_layouts,
 6009                newest_selection_head,
 6010                scrolled_content_origin,
 6011                window,
 6012                cx,
 6013            );
 6014        }
 6015
 6016        const POLE_WIDTH: Pixels = px(2.);
 6017
 6018        let line_layout =
 6019            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 6020        let target_column = target_display_point.column() as usize;
 6021
 6022        let target_x = line_layout.x_for_index(target_column);
 6023        let target_y =
 6024            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 6025
 6026        let flag_on_right = target_x < text_bounds.size.width / 2.;
 6027
 6028        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 6029        border_color.l += 0.001;
 6030
 6031        let mut element = v_flex()
 6032            .items_end()
 6033            .when(flag_on_right, |el| el.items_start())
 6034            .child(if flag_on_right {
 6035                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 6036                    .rounded_bl(px(0.))
 6037                    .rounded_tl(px(0.))
 6038                    .border_l_2()
 6039                    .border_color(border_color)
 6040            } else {
 6041                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 6042                    .rounded_br(px(0.))
 6043                    .rounded_tr(px(0.))
 6044                    .border_r_2()
 6045                    .border_color(border_color)
 6046            })
 6047            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 6048            .into_any();
 6049
 6050        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 6051
 6052        let mut origin = scrolled_content_origin + point(target_x, target_y)
 6053            - point(
 6054                if flag_on_right {
 6055                    POLE_WIDTH
 6056                } else {
 6057                    size.width - POLE_WIDTH
 6058                },
 6059                size.height - line_height,
 6060            );
 6061
 6062        origin.x = origin.x.max(content_origin.x);
 6063
 6064        element.prepaint_at(origin, window, cx);
 6065
 6066        Some((element, origin))
 6067    }
 6068
 6069    #[allow(clippy::too_many_arguments)]
 6070    fn render_edit_prediction_scroll_popover(
 6071        &mut self,
 6072        to_y: impl Fn(Size<Pixels>) -> Pixels,
 6073        scroll_icon: IconName,
 6074        visible_row_range: Range<DisplayRow>,
 6075        line_layouts: &[LineWithInvisibles],
 6076        newest_selection_head: Option<DisplayPoint>,
 6077        scrolled_content_origin: gpui::Point<Pixels>,
 6078        window: &mut Window,
 6079        cx: &mut App,
 6080    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 6081        let mut element = self
 6082            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 6083            .into_any();
 6084
 6085        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 6086
 6087        let cursor = newest_selection_head?;
 6088        let cursor_row_layout =
 6089            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 6090        let cursor_column = cursor.column() as usize;
 6091
 6092        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 6093
 6094        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 6095
 6096        element.prepaint_at(origin, window, cx);
 6097        Some((element, origin))
 6098    }
 6099
 6100    #[allow(clippy::too_many_arguments)]
 6101    fn render_edit_prediction_eager_jump_popover(
 6102        &mut self,
 6103        text_bounds: &Bounds<Pixels>,
 6104        content_origin: gpui::Point<Pixels>,
 6105        editor_snapshot: &EditorSnapshot,
 6106        visible_row_range: Range<DisplayRow>,
 6107        scroll_top: f32,
 6108        scroll_bottom: f32,
 6109        line_height: Pixels,
 6110        scroll_pixel_position: gpui::Point<Pixels>,
 6111        target_display_point: DisplayPoint,
 6112        editor_width: Pixels,
 6113        window: &mut Window,
 6114        cx: &mut App,
 6115    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 6116        if target_display_point.row().as_f32() < scroll_top {
 6117            let mut element = self
 6118                .render_edit_prediction_line_popover(
 6119                    "Jump to Edit",
 6120                    Some(IconName::ArrowUp),
 6121                    window,
 6122                    cx,
 6123                )?
 6124                .into_any();
 6125
 6126            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 6127            let offset = point(
 6128                (text_bounds.size.width - size.width) / 2.,
 6129                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 6130            );
 6131
 6132            let origin = text_bounds.origin + offset;
 6133            element.prepaint_at(origin, window, cx);
 6134            Some((element, origin))
 6135        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 6136            let mut element = self
 6137                .render_edit_prediction_line_popover(
 6138                    "Jump to Edit",
 6139                    Some(IconName::ArrowDown),
 6140                    window,
 6141                    cx,
 6142                )?
 6143                .into_any();
 6144
 6145            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 6146            let offset = point(
 6147                (text_bounds.size.width - size.width) / 2.,
 6148                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 6149            );
 6150
 6151            let origin = text_bounds.origin + offset;
 6152            element.prepaint_at(origin, window, cx);
 6153            Some((element, origin))
 6154        } else {
 6155            self.render_edit_prediction_end_of_line_popover(
 6156                "Jump to Edit",
 6157                editor_snapshot,
 6158                visible_row_range,
 6159                target_display_point,
 6160                line_height,
 6161                scroll_pixel_position,
 6162                content_origin,
 6163                editor_width,
 6164                window,
 6165                cx,
 6166            )
 6167        }
 6168    }
 6169
 6170    #[allow(clippy::too_many_arguments)]
 6171    fn render_edit_prediction_end_of_line_popover(
 6172        self: &mut Editor,
 6173        label: &'static str,
 6174        editor_snapshot: &EditorSnapshot,
 6175        visible_row_range: Range<DisplayRow>,
 6176        target_display_point: DisplayPoint,
 6177        line_height: Pixels,
 6178        scroll_pixel_position: gpui::Point<Pixels>,
 6179        content_origin: gpui::Point<Pixels>,
 6180        editor_width: Pixels,
 6181        window: &mut Window,
 6182        cx: &mut App,
 6183    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 6184        let target_line_end = DisplayPoint::new(
 6185            target_display_point.row(),
 6186            editor_snapshot.line_len(target_display_point.row()),
 6187        );
 6188
 6189        let mut element = self
 6190            .render_edit_prediction_line_popover(label, None, window, cx)?
 6191            .into_any();
 6192
 6193        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 6194
 6195        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 6196
 6197        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 6198        let mut origin = start_point
 6199            + line_origin
 6200            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 6201        origin.x = origin.x.max(content_origin.x);
 6202
 6203        let max_x = content_origin.x + editor_width - size.width;
 6204
 6205        if origin.x > max_x {
 6206            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 6207
 6208            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 6209                origin.y += offset;
 6210                IconName::ArrowUp
 6211            } else {
 6212                origin.y -= offset;
 6213                IconName::ArrowDown
 6214            };
 6215
 6216            element = self
 6217                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 6218                .into_any();
 6219
 6220            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 6221
 6222            origin.x = content_origin.x + editor_width - size.width - px(2.);
 6223        }
 6224
 6225        element.prepaint_at(origin, window, cx);
 6226        Some((element, origin))
 6227    }
 6228
 6229    #[allow(clippy::too_many_arguments)]
 6230    fn render_edit_prediction_diff_popover(
 6231        self: &Editor,
 6232        text_bounds: &Bounds<Pixels>,
 6233        content_origin: gpui::Point<Pixels>,
 6234        editor_snapshot: &EditorSnapshot,
 6235        visible_row_range: Range<DisplayRow>,
 6236        line_layouts: &[LineWithInvisibles],
 6237        line_height: Pixels,
 6238        scroll_pixel_position: gpui::Point<Pixels>,
 6239        newest_selection_head: Option<DisplayPoint>,
 6240        editor_width: Pixels,
 6241        style: &EditorStyle,
 6242        edits: &Vec<(Range<Anchor>, String)>,
 6243        edit_preview: &Option<language::EditPreview>,
 6244        snapshot: &language::BufferSnapshot,
 6245        window: &mut Window,
 6246        cx: &mut App,
 6247    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 6248        let edit_start = edits
 6249            .first()
 6250            .unwrap()
 6251            .0
 6252            .start
 6253            .to_display_point(editor_snapshot);
 6254        let edit_end = edits
 6255            .last()
 6256            .unwrap()
 6257            .0
 6258            .end
 6259            .to_display_point(editor_snapshot);
 6260
 6261        let is_visible = visible_row_range.contains(&edit_start.row())
 6262            || visible_row_range.contains(&edit_end.row());
 6263        if !is_visible {
 6264            return None;
 6265        }
 6266
 6267        let highlighted_edits =
 6268            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 6269
 6270        let styled_text = highlighted_edits.to_styled_text(&style.text);
 6271        let line_count = highlighted_edits.text.lines().count();
 6272
 6273        const BORDER_WIDTH: Pixels = px(1.);
 6274
 6275        let mut element = h_flex()
 6276            .items_start()
 6277            .child(
 6278                h_flex()
 6279                    .bg(cx.theme().colors().editor_background)
 6280                    .border(BORDER_WIDTH)
 6281                    .shadow_sm()
 6282                    .border_color(cx.theme().colors().border)
 6283                    .rounded_l_lg()
 6284                    .when(line_count > 1, |el| el.rounded_br_lg())
 6285                    .pr_1()
 6286                    .child(styled_text),
 6287            )
 6288            .child(
 6289                h_flex()
 6290                    .h(line_height + BORDER_WIDTH * px(2.))
 6291                    .px_1p5()
 6292                    .gap_1()
 6293                    // Workaround: For some reason, there's a gap if we don't do this
 6294                    .ml(-BORDER_WIDTH)
 6295                    .shadow(smallvec![gpui::BoxShadow {
 6296                        color: gpui::black().opacity(0.05),
 6297                        offset: point(px(1.), px(1.)),
 6298                        blur_radius: px(2.),
 6299                        spread_radius: px(0.),
 6300                    }])
 6301                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 6302                    .border(BORDER_WIDTH)
 6303                    .border_color(cx.theme().colors().border)
 6304                    .rounded_r_lg()
 6305                    .children(self.render_edit_prediction_accept_keybind(window, cx)),
 6306            )
 6307            .into_any();
 6308
 6309        let longest_row =
 6310            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 6311        let longest_line_width = if visible_row_range.contains(&longest_row) {
 6312            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 6313        } else {
 6314            layout_line(
 6315                longest_row,
 6316                editor_snapshot,
 6317                style,
 6318                editor_width,
 6319                |_| false,
 6320                window,
 6321                cx,
 6322            )
 6323            .width
 6324        };
 6325
 6326        let viewport_bounds =
 6327            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 6328                right: -EditorElement::SCROLLBAR_WIDTH,
 6329                ..Default::default()
 6330            });
 6331
 6332        let x_after_longest =
 6333            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 6334                - scroll_pixel_position.x;
 6335
 6336        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 6337
 6338        // Fully visible if it can be displayed within the window (allow overlapping other
 6339        // panes). However, this is only allowed if the popover starts within text_bounds.
 6340        let can_position_to_the_right = x_after_longest < text_bounds.right()
 6341            && x_after_longest + element_bounds.width < viewport_bounds.right();
 6342
 6343        let mut origin = if can_position_to_the_right {
 6344            point(
 6345                x_after_longest,
 6346                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 6347                    - scroll_pixel_position.y,
 6348            )
 6349        } else {
 6350            let cursor_row = newest_selection_head.map(|head| head.row());
 6351            let above_edit = edit_start
 6352                .row()
 6353                .0
 6354                .checked_sub(line_count as u32)
 6355                .map(DisplayRow);
 6356            let below_edit = Some(edit_end.row() + 1);
 6357            let above_cursor =
 6358                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 6359            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 6360
 6361            // Place the edit popover adjacent to the edit if there is a location
 6362            // available that is onscreen and does not obscure the cursor. Otherwise,
 6363            // place it adjacent to the cursor.
 6364            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 6365                .into_iter()
 6366                .flatten()
 6367                .find(|&start_row| {
 6368                    let end_row = start_row + line_count as u32;
 6369                    visible_row_range.contains(&start_row)
 6370                        && visible_row_range.contains(&end_row)
 6371                        && cursor_row.map_or(true, |cursor_row| {
 6372                            !((start_row..end_row).contains(&cursor_row))
 6373                        })
 6374                })?;
 6375
 6376            content_origin
 6377                + point(
 6378                    -scroll_pixel_position.x,
 6379                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 6380                )
 6381        };
 6382
 6383        origin.x -= BORDER_WIDTH;
 6384
 6385        window.defer_draw(element, origin, 1);
 6386
 6387        // Do not return an element, since it will already be drawn due to defer_draw.
 6388        None
 6389    }
 6390
 6391    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 6392        px(30.)
 6393    }
 6394
 6395    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 6396        if self.read_only(cx) {
 6397            cx.theme().players().read_only()
 6398        } else {
 6399            self.style.as_ref().unwrap().local_player
 6400        }
 6401    }
 6402
 6403    fn render_edit_prediction_accept_keybind(&self, window: &mut Window, cx: &App) -> Option<Div> {
 6404        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 6405        let accept_keystroke = accept_binding.keystroke()?;
 6406
 6407        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 6408
 6409        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 6410            Color::Accent
 6411        } else {
 6412            Color::Muted
 6413        };
 6414
 6415        h_flex()
 6416            .px_0p5()
 6417            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 6418            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 6419            .text_size(TextSize::XSmall.rems(cx))
 6420            .child(h_flex().children(ui::render_modifiers(
 6421                &accept_keystroke.modifiers,
 6422                PlatformStyle::platform(),
 6423                Some(modifiers_color),
 6424                Some(IconSize::XSmall.rems().into()),
 6425                true,
 6426            )))
 6427            .when(is_platform_style_mac, |parent| {
 6428                parent.child(accept_keystroke.key.clone())
 6429            })
 6430            .when(!is_platform_style_mac, |parent| {
 6431                parent.child(
 6432                    Key::new(
 6433                        util::capitalize(&accept_keystroke.key),
 6434                        Some(Color::Default),
 6435                    )
 6436                    .size(Some(IconSize::XSmall.rems().into())),
 6437                )
 6438            })
 6439            .into()
 6440    }
 6441
 6442    fn render_edit_prediction_line_popover(
 6443        &self,
 6444        label: impl Into<SharedString>,
 6445        icon: Option<IconName>,
 6446        window: &mut Window,
 6447        cx: &App,
 6448    ) -> Option<Div> {
 6449        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 6450
 6451        let result = h_flex()
 6452            .py_0p5()
 6453            .pl_1()
 6454            .pr(padding_right)
 6455            .gap_1()
 6456            .rounded(px(6.))
 6457            .border_1()
 6458            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 6459            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 6460            .shadow_sm()
 6461            .children(self.render_edit_prediction_accept_keybind(window, cx))
 6462            .child(Label::new(label).size(LabelSize::Small))
 6463            .when_some(icon, |element, icon| {
 6464                element.child(
 6465                    div()
 6466                        .mt(px(1.5))
 6467                        .child(Icon::new(icon).size(IconSize::Small)),
 6468                )
 6469            });
 6470
 6471        Some(result)
 6472    }
 6473
 6474    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 6475        let accent_color = cx.theme().colors().text_accent;
 6476        let editor_bg_color = cx.theme().colors().editor_background;
 6477        editor_bg_color.blend(accent_color.opacity(0.1))
 6478    }
 6479
 6480    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 6481        let accent_color = cx.theme().colors().text_accent;
 6482        let editor_bg_color = cx.theme().colors().editor_background;
 6483        editor_bg_color.blend(accent_color.opacity(0.6))
 6484    }
 6485
 6486    #[allow(clippy::too_many_arguments)]
 6487    fn render_edit_prediction_cursor_popover(
 6488        &self,
 6489        min_width: Pixels,
 6490        max_width: Pixels,
 6491        cursor_point: Point,
 6492        style: &EditorStyle,
 6493        accept_keystroke: Option<&gpui::Keystroke>,
 6494        _window: &Window,
 6495        cx: &mut Context<Editor>,
 6496    ) -> Option<AnyElement> {
 6497        let provider = self.edit_prediction_provider.as_ref()?;
 6498
 6499        if provider.provider.needs_terms_acceptance(cx) {
 6500            return Some(
 6501                h_flex()
 6502                    .min_w(min_width)
 6503                    .flex_1()
 6504                    .px_2()
 6505                    .py_1()
 6506                    .gap_3()
 6507                    .elevation_2(cx)
 6508                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 6509                    .id("accept-terms")
 6510                    .cursor_pointer()
 6511                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 6512                    .on_click(cx.listener(|this, _event, window, cx| {
 6513                        cx.stop_propagation();
 6514                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 6515                        window.dispatch_action(
 6516                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 6517                            cx,
 6518                        );
 6519                    }))
 6520                    .child(
 6521                        h_flex()
 6522                            .flex_1()
 6523                            .gap_2()
 6524                            .child(Icon::new(IconName::ZedPredict))
 6525                            .child(Label::new("Accept Terms of Service"))
 6526                            .child(div().w_full())
 6527                            .child(
 6528                                Icon::new(IconName::ArrowUpRight)
 6529                                    .color(Color::Muted)
 6530                                    .size(IconSize::Small),
 6531                            )
 6532                            .into_any_element(),
 6533                    )
 6534                    .into_any(),
 6535            );
 6536        }
 6537
 6538        let is_refreshing = provider.provider.is_refreshing(cx);
 6539
 6540        fn pending_completion_container() -> Div {
 6541            h_flex()
 6542                .h_full()
 6543                .flex_1()
 6544                .gap_2()
 6545                .child(Icon::new(IconName::ZedPredict))
 6546        }
 6547
 6548        let completion = match &self.active_inline_completion {
 6549            Some(prediction) => {
 6550                if !self.has_visible_completions_menu() {
 6551                    const RADIUS: Pixels = px(6.);
 6552                    const BORDER_WIDTH: Pixels = px(1.);
 6553
 6554                    return Some(
 6555                        h_flex()
 6556                            .elevation_2(cx)
 6557                            .border(BORDER_WIDTH)
 6558                            .border_color(cx.theme().colors().border)
 6559                            .rounded(RADIUS)
 6560                            .rounded_tl(px(0.))
 6561                            .overflow_hidden()
 6562                            .child(div().px_1p5().child(match &prediction.completion {
 6563                                InlineCompletion::Move { target, snapshot } => {
 6564                                    use text::ToPoint as _;
 6565                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 6566                                    {
 6567                                        Icon::new(IconName::ZedPredictDown)
 6568                                    } else {
 6569                                        Icon::new(IconName::ZedPredictUp)
 6570                                    }
 6571                                }
 6572                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 6573                            }))
 6574                            .child(
 6575                                h_flex()
 6576                                    .gap_1()
 6577                                    .py_1()
 6578                                    .px_2()
 6579                                    .rounded_r(RADIUS - BORDER_WIDTH)
 6580                                    .border_l_1()
 6581                                    .border_color(cx.theme().colors().border)
 6582                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 6583                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 6584                                        el.child(
 6585                                            Label::new("Hold")
 6586                                                .size(LabelSize::Small)
 6587                                                .line_height_style(LineHeightStyle::UiLabel),
 6588                                        )
 6589                                    })
 6590                                    .child(h_flex().children(ui::render_modifiers(
 6591                                        &accept_keystroke?.modifiers,
 6592                                        PlatformStyle::platform(),
 6593                                        Some(Color::Default),
 6594                                        Some(IconSize::XSmall.rems().into()),
 6595                                        false,
 6596                                    ))),
 6597                            )
 6598                            .into_any(),
 6599                    );
 6600                }
 6601
 6602                self.render_edit_prediction_cursor_popover_preview(
 6603                    prediction,
 6604                    cursor_point,
 6605                    style,
 6606                    cx,
 6607                )?
 6608            }
 6609
 6610            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 6611                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 6612                    stale_completion,
 6613                    cursor_point,
 6614                    style,
 6615                    cx,
 6616                )?,
 6617
 6618                None => {
 6619                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 6620                }
 6621            },
 6622
 6623            None => pending_completion_container().child(Label::new("No Prediction")),
 6624        };
 6625
 6626        let completion = if is_refreshing {
 6627            completion
 6628                .with_animation(
 6629                    "loading-completion",
 6630                    Animation::new(Duration::from_secs(2))
 6631                        .repeat()
 6632                        .with_easing(pulsating_between(0.4, 0.8)),
 6633                    |label, delta| label.opacity(delta),
 6634                )
 6635                .into_any_element()
 6636        } else {
 6637            completion.into_any_element()
 6638        };
 6639
 6640        let has_completion = self.active_inline_completion.is_some();
 6641
 6642        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 6643        Some(
 6644            h_flex()
 6645                .min_w(min_width)
 6646                .max_w(max_width)
 6647                .flex_1()
 6648                .elevation_2(cx)
 6649                .border_color(cx.theme().colors().border)
 6650                .child(
 6651                    div()
 6652                        .flex_1()
 6653                        .py_1()
 6654                        .px_2()
 6655                        .overflow_hidden()
 6656                        .child(completion),
 6657                )
 6658                .when_some(accept_keystroke, |el, accept_keystroke| {
 6659                    if !accept_keystroke.modifiers.modified() {
 6660                        return el;
 6661                    }
 6662
 6663                    el.child(
 6664                        h_flex()
 6665                            .h_full()
 6666                            .border_l_1()
 6667                            .rounded_r_lg()
 6668                            .border_color(cx.theme().colors().border)
 6669                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 6670                            .gap_1()
 6671                            .py_1()
 6672                            .px_2()
 6673                            .child(
 6674                                h_flex()
 6675                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 6676                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 6677                                    .child(h_flex().children(ui::render_modifiers(
 6678                                        &accept_keystroke.modifiers,
 6679                                        PlatformStyle::platform(),
 6680                                        Some(if !has_completion {
 6681                                            Color::Muted
 6682                                        } else {
 6683                                            Color::Default
 6684                                        }),
 6685                                        None,
 6686                                        false,
 6687                                    ))),
 6688                            )
 6689                            .child(Label::new("Preview").into_any_element())
 6690                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 6691                    )
 6692                })
 6693                .into_any(),
 6694        )
 6695    }
 6696
 6697    fn render_edit_prediction_cursor_popover_preview(
 6698        &self,
 6699        completion: &InlineCompletionState,
 6700        cursor_point: Point,
 6701        style: &EditorStyle,
 6702        cx: &mut Context<Editor>,
 6703    ) -> Option<Div> {
 6704        use text::ToPoint as _;
 6705
 6706        fn render_relative_row_jump(
 6707            prefix: impl Into<String>,
 6708            current_row: u32,
 6709            target_row: u32,
 6710        ) -> Div {
 6711            let (row_diff, arrow) = if target_row < current_row {
 6712                (current_row - target_row, IconName::ArrowUp)
 6713            } else {
 6714                (target_row - current_row, IconName::ArrowDown)
 6715            };
 6716
 6717            h_flex()
 6718                .child(
 6719                    Label::new(format!("{}{}", prefix.into(), row_diff))
 6720                        .color(Color::Muted)
 6721                        .size(LabelSize::Small),
 6722                )
 6723                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 6724        }
 6725
 6726        match &completion.completion {
 6727            InlineCompletion::Move {
 6728                target, snapshot, ..
 6729            } => Some(
 6730                h_flex()
 6731                    .px_2()
 6732                    .gap_2()
 6733                    .flex_1()
 6734                    .child(
 6735                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 6736                            Icon::new(IconName::ZedPredictDown)
 6737                        } else {
 6738                            Icon::new(IconName::ZedPredictUp)
 6739                        },
 6740                    )
 6741                    .child(Label::new("Jump to Edit")),
 6742            ),
 6743
 6744            InlineCompletion::Edit {
 6745                edits,
 6746                edit_preview,
 6747                snapshot,
 6748                display_mode: _,
 6749            } => {
 6750                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 6751
 6752                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 6753                    &snapshot,
 6754                    &edits,
 6755                    edit_preview.as_ref()?,
 6756                    true,
 6757                    cx,
 6758                )
 6759                .first_line_preview();
 6760
 6761                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 6762                    .with_highlights(&style.text, highlighted_edits.highlights);
 6763
 6764                let preview = h_flex()
 6765                    .gap_1()
 6766                    .min_w_16()
 6767                    .child(styled_text)
 6768                    .when(has_more_lines, |parent| parent.child(""));
 6769
 6770                let left = if first_edit_row != cursor_point.row {
 6771                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 6772                        .into_any_element()
 6773                } else {
 6774                    Icon::new(IconName::ZedPredict).into_any_element()
 6775                };
 6776
 6777                Some(
 6778                    h_flex()
 6779                        .h_full()
 6780                        .flex_1()
 6781                        .gap_2()
 6782                        .pr_1()
 6783                        .overflow_x_hidden()
 6784                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 6785                        .child(left)
 6786                        .child(preview),
 6787                )
 6788            }
 6789        }
 6790    }
 6791
 6792    fn render_context_menu(
 6793        &self,
 6794        style: &EditorStyle,
 6795        max_height_in_lines: u32,
 6796        y_flipped: bool,
 6797        window: &mut Window,
 6798        cx: &mut Context<Editor>,
 6799    ) -> Option<AnyElement> {
 6800        let menu = self.context_menu.borrow();
 6801        let menu = menu.as_ref()?;
 6802        if !menu.visible() {
 6803            return None;
 6804        };
 6805        Some(menu.render(style, max_height_in_lines, y_flipped, window, cx))
 6806    }
 6807
 6808    fn render_context_menu_aside(
 6809        &mut self,
 6810        max_size: Size<Pixels>,
 6811        window: &mut Window,
 6812        cx: &mut Context<Editor>,
 6813    ) -> Option<AnyElement> {
 6814        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 6815            if menu.visible() {
 6816                menu.render_aside(self, max_size, window, cx)
 6817            } else {
 6818                None
 6819            }
 6820        })
 6821    }
 6822
 6823    fn hide_context_menu(
 6824        &mut self,
 6825        window: &mut Window,
 6826        cx: &mut Context<Self>,
 6827    ) -> Option<CodeContextMenu> {
 6828        cx.notify();
 6829        self.completion_tasks.clear();
 6830        let context_menu = self.context_menu.borrow_mut().take();
 6831        self.stale_inline_completion_in_menu.take();
 6832        self.update_visible_inline_completion(window, cx);
 6833        context_menu
 6834    }
 6835
 6836    fn show_snippet_choices(
 6837        &mut self,
 6838        choices: &Vec<String>,
 6839        selection: Range<Anchor>,
 6840        cx: &mut Context<Self>,
 6841    ) {
 6842        if selection.start.buffer_id.is_none() {
 6843            return;
 6844        }
 6845        let buffer_id = selection.start.buffer_id.unwrap();
 6846        let buffer = self.buffer().read(cx).buffer(buffer_id);
 6847        let id = post_inc(&mut self.next_completion_id);
 6848
 6849        if let Some(buffer) = buffer {
 6850            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 6851                CompletionsMenu::new_snippet_choices(id, true, choices, selection, buffer),
 6852            ));
 6853        }
 6854    }
 6855
 6856    pub fn insert_snippet(
 6857        &mut self,
 6858        insertion_ranges: &[Range<usize>],
 6859        snippet: Snippet,
 6860        window: &mut Window,
 6861        cx: &mut Context<Self>,
 6862    ) -> Result<()> {
 6863        struct Tabstop<T> {
 6864            is_end_tabstop: bool,
 6865            ranges: Vec<Range<T>>,
 6866            choices: Option<Vec<String>>,
 6867        }
 6868
 6869        let tabstops = self.buffer.update(cx, |buffer, cx| {
 6870            let snippet_text: Arc<str> = snippet.text.clone().into();
 6871            buffer.edit(
 6872                insertion_ranges
 6873                    .iter()
 6874                    .cloned()
 6875                    .map(|range| (range, snippet_text.clone())),
 6876                Some(AutoindentMode::EachLine),
 6877                cx,
 6878            );
 6879
 6880            let snapshot = &*buffer.read(cx);
 6881            let snippet = &snippet;
 6882            snippet
 6883                .tabstops
 6884                .iter()
 6885                .map(|tabstop| {
 6886                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 6887                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 6888                    });
 6889                    let mut tabstop_ranges = tabstop
 6890                        .ranges
 6891                        .iter()
 6892                        .flat_map(|tabstop_range| {
 6893                            let mut delta = 0_isize;
 6894                            insertion_ranges.iter().map(move |insertion_range| {
 6895                                let insertion_start = insertion_range.start as isize + delta;
 6896                                delta +=
 6897                                    snippet.text.len() as isize - insertion_range.len() as isize;
 6898
 6899                                let start = ((insertion_start + tabstop_range.start) as usize)
 6900                                    .min(snapshot.len());
 6901                                let end = ((insertion_start + tabstop_range.end) as usize)
 6902                                    .min(snapshot.len());
 6903                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 6904                            })
 6905                        })
 6906                        .collect::<Vec<_>>();
 6907                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 6908
 6909                    Tabstop {
 6910                        is_end_tabstop,
 6911                        ranges: tabstop_ranges,
 6912                        choices: tabstop.choices.clone(),
 6913                    }
 6914                })
 6915                .collect::<Vec<_>>()
 6916        });
 6917        if let Some(tabstop) = tabstops.first() {
 6918            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 6919                s.select_ranges(tabstop.ranges.iter().cloned());
 6920            });
 6921
 6922            if let Some(choices) = &tabstop.choices {
 6923                if let Some(selection) = tabstop.ranges.first() {
 6924                    self.show_snippet_choices(choices, selection.clone(), cx)
 6925                }
 6926            }
 6927
 6928            // If we're already at the last tabstop and it's at the end of the snippet,
 6929            // we're done, we don't need to keep the state around.
 6930            if !tabstop.is_end_tabstop {
 6931                let choices = tabstops
 6932                    .iter()
 6933                    .map(|tabstop| tabstop.choices.clone())
 6934                    .collect();
 6935
 6936                let ranges = tabstops
 6937                    .into_iter()
 6938                    .map(|tabstop| tabstop.ranges)
 6939                    .collect::<Vec<_>>();
 6940
 6941                self.snippet_stack.push(SnippetState {
 6942                    active_index: 0,
 6943                    ranges,
 6944                    choices,
 6945                });
 6946            }
 6947
 6948            // Check whether the just-entered snippet ends with an auto-closable bracket.
 6949            if self.autoclose_regions.is_empty() {
 6950                let snapshot = self.buffer.read(cx).snapshot(cx);
 6951                for selection in &mut self.selections.all::<Point>(cx) {
 6952                    let selection_head = selection.head();
 6953                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 6954                        continue;
 6955                    };
 6956
 6957                    let mut bracket_pair = None;
 6958                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 6959                    let prev_chars = snapshot
 6960                        .reversed_chars_at(selection_head)
 6961                        .collect::<String>();
 6962                    for (pair, enabled) in scope.brackets() {
 6963                        if enabled
 6964                            && pair.close
 6965                            && prev_chars.starts_with(pair.start.as_str())
 6966                            && next_chars.starts_with(pair.end.as_str())
 6967                        {
 6968                            bracket_pair = Some(pair.clone());
 6969                            break;
 6970                        }
 6971                    }
 6972                    if let Some(pair) = bracket_pair {
 6973                        let start = snapshot.anchor_after(selection_head);
 6974                        let end = snapshot.anchor_after(selection_head);
 6975                        self.autoclose_regions.push(AutocloseRegion {
 6976                            selection_id: selection.id,
 6977                            range: start..end,
 6978                            pair,
 6979                        });
 6980                    }
 6981                }
 6982            }
 6983        }
 6984        Ok(())
 6985    }
 6986
 6987    pub fn move_to_next_snippet_tabstop(
 6988        &mut self,
 6989        window: &mut Window,
 6990        cx: &mut Context<Self>,
 6991    ) -> bool {
 6992        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 6993    }
 6994
 6995    pub fn move_to_prev_snippet_tabstop(
 6996        &mut self,
 6997        window: &mut Window,
 6998        cx: &mut Context<Self>,
 6999    ) -> bool {
 7000        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 7001    }
 7002
 7003    pub fn move_to_snippet_tabstop(
 7004        &mut self,
 7005        bias: Bias,
 7006        window: &mut Window,
 7007        cx: &mut Context<Self>,
 7008    ) -> bool {
 7009        if let Some(mut snippet) = self.snippet_stack.pop() {
 7010            match bias {
 7011                Bias::Left => {
 7012                    if snippet.active_index > 0 {
 7013                        snippet.active_index -= 1;
 7014                    } else {
 7015                        self.snippet_stack.push(snippet);
 7016                        return false;
 7017                    }
 7018                }
 7019                Bias::Right => {
 7020                    if snippet.active_index + 1 < snippet.ranges.len() {
 7021                        snippet.active_index += 1;
 7022                    } else {
 7023                        self.snippet_stack.push(snippet);
 7024                        return false;
 7025                    }
 7026                }
 7027            }
 7028            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 7029                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 7030                    s.select_anchor_ranges(current_ranges.iter().cloned())
 7031                });
 7032
 7033                if let Some(choices) = &snippet.choices[snippet.active_index] {
 7034                    if let Some(selection) = current_ranges.first() {
 7035                        self.show_snippet_choices(&choices, selection.clone(), cx);
 7036                    }
 7037                }
 7038
 7039                // If snippet state is not at the last tabstop, push it back on the stack
 7040                if snippet.active_index + 1 < snippet.ranges.len() {
 7041                    self.snippet_stack.push(snippet);
 7042                }
 7043                return true;
 7044            }
 7045        }
 7046
 7047        false
 7048    }
 7049
 7050    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7051        self.transact(window, cx, |this, window, cx| {
 7052            this.select_all(&SelectAll, window, cx);
 7053            this.insert("", window, cx);
 7054        });
 7055    }
 7056
 7057    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 7058        self.transact(window, cx, |this, window, cx| {
 7059            this.select_autoclose_pair(window, cx);
 7060            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 7061            if !this.linked_edit_ranges.is_empty() {
 7062                let selections = this.selections.all::<MultiBufferPoint>(cx);
 7063                let snapshot = this.buffer.read(cx).snapshot(cx);
 7064
 7065                for selection in selections.iter() {
 7066                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 7067                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 7068                    if selection_start.buffer_id != selection_end.buffer_id {
 7069                        continue;
 7070                    }
 7071                    if let Some(ranges) =
 7072                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 7073                    {
 7074                        for (buffer, entries) in ranges {
 7075                            linked_ranges.entry(buffer).or_default().extend(entries);
 7076                        }
 7077                    }
 7078                }
 7079            }
 7080
 7081            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 7082            if !this.selections.line_mode {
 7083                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 7084                for selection in &mut selections {
 7085                    if selection.is_empty() {
 7086                        let old_head = selection.head();
 7087                        let mut new_head =
 7088                            movement::left(&display_map, old_head.to_display_point(&display_map))
 7089                                .to_point(&display_map);
 7090                        if let Some((buffer, line_buffer_range)) = display_map
 7091                            .buffer_snapshot
 7092                            .buffer_line_for_row(MultiBufferRow(old_head.row))
 7093                        {
 7094                            let indent_size =
 7095                                buffer.indent_size_for_line(line_buffer_range.start.row);
 7096                            let indent_len = match indent_size.kind {
 7097                                IndentKind::Space => {
 7098                                    buffer.settings_at(line_buffer_range.start, cx).tab_size
 7099                                }
 7100                                IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 7101                            };
 7102                            if old_head.column <= indent_size.len && old_head.column > 0 {
 7103                                let indent_len = indent_len.get();
 7104                                new_head = cmp::min(
 7105                                    new_head,
 7106                                    MultiBufferPoint::new(
 7107                                        old_head.row,
 7108                                        ((old_head.column - 1) / indent_len) * indent_len,
 7109                                    ),
 7110                                );
 7111                            }
 7112                        }
 7113
 7114                        selection.set_head(new_head, SelectionGoal::None);
 7115                    }
 7116                }
 7117            }
 7118
 7119            this.signature_help_state.set_backspace_pressed(true);
 7120            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 7121                s.select(selections)
 7122            });
 7123            this.insert("", window, cx);
 7124            let empty_str: Arc<str> = Arc::from("");
 7125            for (buffer, edits) in linked_ranges {
 7126                let snapshot = buffer.read(cx).snapshot();
 7127                use text::ToPoint as TP;
 7128
 7129                let edits = edits
 7130                    .into_iter()
 7131                    .map(|range| {
 7132                        let end_point = TP::to_point(&range.end, &snapshot);
 7133                        let mut start_point = TP::to_point(&range.start, &snapshot);
 7134
 7135                        if end_point == start_point {
 7136                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 7137                                .saturating_sub(1);
 7138                            start_point =
 7139                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 7140                        };
 7141
 7142                        (start_point..end_point, empty_str.clone())
 7143                    })
 7144                    .sorted_by_key(|(range, _)| range.start)
 7145                    .collect::<Vec<_>>();
 7146                buffer.update(cx, |this, cx| {
 7147                    this.edit(edits, None, cx);
 7148                })
 7149            }
 7150            this.refresh_inline_completion(true, false, window, cx);
 7151            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 7152        });
 7153    }
 7154
 7155    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 7156        self.transact(window, cx, |this, window, cx| {
 7157            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 7158                let line_mode = s.line_mode;
 7159                s.move_with(|map, selection| {
 7160                    if selection.is_empty() && !line_mode {
 7161                        let cursor = movement::right(map, selection.head());
 7162                        selection.end = cursor;
 7163                        selection.reversed = true;
 7164                        selection.goal = SelectionGoal::None;
 7165                    }
 7166                })
 7167            });
 7168            this.insert("", window, cx);
 7169            this.refresh_inline_completion(true, false, window, cx);
 7170        });
 7171    }
 7172
 7173    pub fn tab_prev(&mut self, _: &TabPrev, window: &mut Window, cx: &mut Context<Self>) {
 7174        if self.move_to_prev_snippet_tabstop(window, cx) {
 7175            return;
 7176        }
 7177
 7178        self.outdent(&Outdent, window, cx);
 7179    }
 7180
 7181    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 7182        if self.move_to_next_snippet_tabstop(window, cx) || self.read_only(cx) {
 7183            return;
 7184        }
 7185
 7186        let mut selections = self.selections.all_adjusted(cx);
 7187        let buffer = self.buffer.read(cx);
 7188        let snapshot = buffer.snapshot(cx);
 7189        let rows_iter = selections.iter().map(|s| s.head().row);
 7190        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 7191
 7192        let mut edits = Vec::new();
 7193        let mut prev_edited_row = 0;
 7194        let mut row_delta = 0;
 7195        for selection in &mut selections {
 7196            if selection.start.row != prev_edited_row {
 7197                row_delta = 0;
 7198            }
 7199            prev_edited_row = selection.end.row;
 7200
 7201            // If the selection is non-empty, then increase the indentation of the selected lines.
 7202            if !selection.is_empty() {
 7203                row_delta =
 7204                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 7205                continue;
 7206            }
 7207
 7208            // If the selection is empty and the cursor is in the leading whitespace before the
 7209            // suggested indentation, then auto-indent the line.
 7210            let cursor = selection.head();
 7211            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 7212            if let Some(suggested_indent) =
 7213                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 7214            {
 7215                if cursor.column < suggested_indent.len
 7216                    && cursor.column <= current_indent.len
 7217                    && current_indent.len <= suggested_indent.len
 7218                {
 7219                    selection.start = Point::new(cursor.row, suggested_indent.len);
 7220                    selection.end = selection.start;
 7221                    if row_delta == 0 {
 7222                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 7223                            cursor.row,
 7224                            current_indent,
 7225                            suggested_indent,
 7226                        ));
 7227                        row_delta = suggested_indent.len - current_indent.len;
 7228                    }
 7229                    continue;
 7230                }
 7231            }
 7232
 7233            // Otherwise, insert a hard or soft tab.
 7234            let settings = buffer.settings_at(cursor, cx);
 7235            let tab_size = if settings.hard_tabs {
 7236                IndentSize::tab()
 7237            } else {
 7238                let tab_size = settings.tab_size.get();
 7239                let char_column = snapshot
 7240                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 7241                    .flat_map(str::chars)
 7242                    .count()
 7243                    + row_delta as usize;
 7244                let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
 7245                IndentSize::spaces(chars_to_next_tab_stop)
 7246            };
 7247            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 7248            selection.end = selection.start;
 7249            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 7250            row_delta += tab_size.len;
 7251        }
 7252
 7253        self.transact(window, cx, |this, window, cx| {
 7254            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 7255            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 7256                s.select(selections)
 7257            });
 7258            this.refresh_inline_completion(true, false, window, cx);
 7259        });
 7260    }
 7261
 7262    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 7263        if self.read_only(cx) {
 7264            return;
 7265        }
 7266        let mut selections = self.selections.all::<Point>(cx);
 7267        let mut prev_edited_row = 0;
 7268        let mut row_delta = 0;
 7269        let mut edits = Vec::new();
 7270        let buffer = self.buffer.read(cx);
 7271        let snapshot = buffer.snapshot(cx);
 7272        for selection in &mut selections {
 7273            if selection.start.row != prev_edited_row {
 7274                row_delta = 0;
 7275            }
 7276            prev_edited_row = selection.end.row;
 7277
 7278            row_delta =
 7279                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 7280        }
 7281
 7282        self.transact(window, cx, |this, window, cx| {
 7283            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 7284            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 7285                s.select(selections)
 7286            });
 7287        });
 7288    }
 7289
 7290    fn indent_selection(
 7291        buffer: &MultiBuffer,
 7292        snapshot: &MultiBufferSnapshot,
 7293        selection: &mut Selection<Point>,
 7294        edits: &mut Vec<(Range<Point>, String)>,
 7295        delta_for_start_row: u32,
 7296        cx: &App,
 7297    ) -> u32 {
 7298        let settings = buffer.settings_at(selection.start, cx);
 7299        let tab_size = settings.tab_size.get();
 7300        let indent_kind = if settings.hard_tabs {
 7301            IndentKind::Tab
 7302        } else {
 7303            IndentKind::Space
 7304        };
 7305        let mut start_row = selection.start.row;
 7306        let mut end_row = selection.end.row + 1;
 7307
 7308        // If a selection ends at the beginning of a line, don't indent
 7309        // that last line.
 7310        if selection.end.column == 0 && selection.end.row > selection.start.row {
 7311            end_row -= 1;
 7312        }
 7313
 7314        // Avoid re-indenting a row that has already been indented by a
 7315        // previous selection, but still update this selection's column
 7316        // to reflect that indentation.
 7317        if delta_for_start_row > 0 {
 7318            start_row += 1;
 7319            selection.start.column += delta_for_start_row;
 7320            if selection.end.row == selection.start.row {
 7321                selection.end.column += delta_for_start_row;
 7322            }
 7323        }
 7324
 7325        let mut delta_for_end_row = 0;
 7326        let has_multiple_rows = start_row + 1 != end_row;
 7327        for row in start_row..end_row {
 7328            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 7329            let indent_delta = match (current_indent.kind, indent_kind) {
 7330                (IndentKind::Space, IndentKind::Space) => {
 7331                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 7332                    IndentSize::spaces(columns_to_next_tab_stop)
 7333                }
 7334                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 7335                (_, IndentKind::Tab) => IndentSize::tab(),
 7336            };
 7337
 7338            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 7339                0
 7340            } else {
 7341                selection.start.column
 7342            };
 7343            let row_start = Point::new(row, start);
 7344            edits.push((
 7345                row_start..row_start,
 7346                indent_delta.chars().collect::<String>(),
 7347            ));
 7348
 7349            // Update this selection's endpoints to reflect the indentation.
 7350            if row == selection.start.row {
 7351                selection.start.column += indent_delta.len;
 7352            }
 7353            if row == selection.end.row {
 7354                selection.end.column += indent_delta.len;
 7355                delta_for_end_row = indent_delta.len;
 7356            }
 7357        }
 7358
 7359        if selection.start.row == selection.end.row {
 7360            delta_for_start_row + delta_for_end_row
 7361        } else {
 7362            delta_for_end_row
 7363        }
 7364    }
 7365
 7366    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 7367        if self.read_only(cx) {
 7368            return;
 7369        }
 7370        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7371        let selections = self.selections.all::<Point>(cx);
 7372        let mut deletion_ranges = Vec::new();
 7373        let mut last_outdent = None;
 7374        {
 7375            let buffer = self.buffer.read(cx);
 7376            let snapshot = buffer.snapshot(cx);
 7377            for selection in &selections {
 7378                let settings = buffer.settings_at(selection.start, cx);
 7379                let tab_size = settings.tab_size.get();
 7380                let mut rows = selection.spanned_rows(false, &display_map);
 7381
 7382                // Avoid re-outdenting a row that has already been outdented by a
 7383                // previous selection.
 7384                if let Some(last_row) = last_outdent {
 7385                    if last_row == rows.start {
 7386                        rows.start = rows.start.next_row();
 7387                    }
 7388                }
 7389                let has_multiple_rows = rows.len() > 1;
 7390                for row in rows.iter_rows() {
 7391                    let indent_size = snapshot.indent_size_for_line(row);
 7392                    if indent_size.len > 0 {
 7393                        let deletion_len = match indent_size.kind {
 7394                            IndentKind::Space => {
 7395                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 7396                                if columns_to_prev_tab_stop == 0 {
 7397                                    tab_size
 7398                                } else {
 7399                                    columns_to_prev_tab_stop
 7400                                }
 7401                            }
 7402                            IndentKind::Tab => 1,
 7403                        };
 7404                        let start = if has_multiple_rows
 7405                            || deletion_len > selection.start.column
 7406                            || indent_size.len < selection.start.column
 7407                        {
 7408                            0
 7409                        } else {
 7410                            selection.start.column - deletion_len
 7411                        };
 7412                        deletion_ranges.push(
 7413                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 7414                        );
 7415                        last_outdent = Some(row);
 7416                    }
 7417                }
 7418            }
 7419        }
 7420
 7421        self.transact(window, cx, |this, window, cx| {
 7422            this.buffer.update(cx, |buffer, cx| {
 7423                let empty_str: Arc<str> = Arc::default();
 7424                buffer.edit(
 7425                    deletion_ranges
 7426                        .into_iter()
 7427                        .map(|range| (range, empty_str.clone())),
 7428                    None,
 7429                    cx,
 7430                );
 7431            });
 7432            let selections = this.selections.all::<usize>(cx);
 7433            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 7434                s.select(selections)
 7435            });
 7436        });
 7437    }
 7438
 7439    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 7440        if self.read_only(cx) {
 7441            return;
 7442        }
 7443        let selections = self
 7444            .selections
 7445            .all::<usize>(cx)
 7446            .into_iter()
 7447            .map(|s| s.range());
 7448
 7449        self.transact(window, cx, |this, window, cx| {
 7450            this.buffer.update(cx, |buffer, cx| {
 7451                buffer.autoindent_ranges(selections, cx);
 7452            });
 7453            let selections = this.selections.all::<usize>(cx);
 7454            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 7455                s.select(selections)
 7456            });
 7457        });
 7458    }
 7459
 7460    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 7461        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7462        let selections = self.selections.all::<Point>(cx);
 7463
 7464        let mut new_cursors = Vec::new();
 7465        let mut edit_ranges = Vec::new();
 7466        let mut selections = selections.iter().peekable();
 7467        while let Some(selection) = selections.next() {
 7468            let mut rows = selection.spanned_rows(false, &display_map);
 7469            let goal_display_column = selection.head().to_display_point(&display_map).column();
 7470
 7471            // Accumulate contiguous regions of rows that we want to delete.
 7472            while let Some(next_selection) = selections.peek() {
 7473                let next_rows = next_selection.spanned_rows(false, &display_map);
 7474                if next_rows.start <= rows.end {
 7475                    rows.end = next_rows.end;
 7476                    selections.next().unwrap();
 7477                } else {
 7478                    break;
 7479                }
 7480            }
 7481
 7482            let buffer = &display_map.buffer_snapshot;
 7483            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 7484            let edit_end;
 7485            let cursor_buffer_row;
 7486            if buffer.max_point().row >= rows.end.0 {
 7487                // If there's a line after the range, delete the \n from the end of the row range
 7488                // and position the cursor on the next line.
 7489                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 7490                cursor_buffer_row = rows.end;
 7491            } else {
 7492                // If there isn't a line after the range, delete the \n from the line before the
 7493                // start of the row range and position the cursor there.
 7494                edit_start = edit_start.saturating_sub(1);
 7495                edit_end = buffer.len();
 7496                cursor_buffer_row = rows.start.previous_row();
 7497            }
 7498
 7499            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 7500            *cursor.column_mut() =
 7501                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 7502
 7503            new_cursors.push((
 7504                selection.id,
 7505                buffer.anchor_after(cursor.to_point(&display_map)),
 7506            ));
 7507            edit_ranges.push(edit_start..edit_end);
 7508        }
 7509
 7510        self.transact(window, cx, |this, window, cx| {
 7511            let buffer = this.buffer.update(cx, |buffer, cx| {
 7512                let empty_str: Arc<str> = Arc::default();
 7513                buffer.edit(
 7514                    edit_ranges
 7515                        .into_iter()
 7516                        .map(|range| (range, empty_str.clone())),
 7517                    None,
 7518                    cx,
 7519                );
 7520                buffer.snapshot(cx)
 7521            });
 7522            let new_selections = new_cursors
 7523                .into_iter()
 7524                .map(|(id, cursor)| {
 7525                    let cursor = cursor.to_point(&buffer);
 7526                    Selection {
 7527                        id,
 7528                        start: cursor,
 7529                        end: cursor,
 7530                        reversed: false,
 7531                        goal: SelectionGoal::None,
 7532                    }
 7533                })
 7534                .collect();
 7535
 7536            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 7537                s.select(new_selections);
 7538            });
 7539        });
 7540    }
 7541
 7542    pub fn join_lines_impl(
 7543        &mut self,
 7544        insert_whitespace: bool,
 7545        window: &mut Window,
 7546        cx: &mut Context<Self>,
 7547    ) {
 7548        if self.read_only(cx) {
 7549            return;
 7550        }
 7551        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 7552        for selection in self.selections.all::<Point>(cx) {
 7553            let start = MultiBufferRow(selection.start.row);
 7554            // Treat single line selections as if they include the next line. Otherwise this action
 7555            // would do nothing for single line selections individual cursors.
 7556            let end = if selection.start.row == selection.end.row {
 7557                MultiBufferRow(selection.start.row + 1)
 7558            } else {
 7559                MultiBufferRow(selection.end.row)
 7560            };
 7561
 7562            if let Some(last_row_range) = row_ranges.last_mut() {
 7563                if start <= last_row_range.end {
 7564                    last_row_range.end = end;
 7565                    continue;
 7566                }
 7567            }
 7568            row_ranges.push(start..end);
 7569        }
 7570
 7571        let snapshot = self.buffer.read(cx).snapshot(cx);
 7572        let mut cursor_positions = Vec::new();
 7573        for row_range in &row_ranges {
 7574            let anchor = snapshot.anchor_before(Point::new(
 7575                row_range.end.previous_row().0,
 7576                snapshot.line_len(row_range.end.previous_row()),
 7577            ));
 7578            cursor_positions.push(anchor..anchor);
 7579        }
 7580
 7581        self.transact(window, cx, |this, window, cx| {
 7582            for row_range in row_ranges.into_iter().rev() {
 7583                for row in row_range.iter_rows().rev() {
 7584                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 7585                    let next_line_row = row.next_row();
 7586                    let indent = snapshot.indent_size_for_line(next_line_row);
 7587                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 7588
 7589                    let replace =
 7590                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 7591                            " "
 7592                        } else {
 7593                            ""
 7594                        };
 7595
 7596                    this.buffer.update(cx, |buffer, cx| {
 7597                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 7598                    });
 7599                }
 7600            }
 7601
 7602            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 7603                s.select_anchor_ranges(cursor_positions)
 7604            });
 7605        });
 7606    }
 7607
 7608    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 7609        self.join_lines_impl(true, window, cx);
 7610    }
 7611
 7612    pub fn sort_lines_case_sensitive(
 7613        &mut self,
 7614        _: &SortLinesCaseSensitive,
 7615        window: &mut Window,
 7616        cx: &mut Context<Self>,
 7617    ) {
 7618        self.manipulate_lines(window, cx, |lines| lines.sort())
 7619    }
 7620
 7621    pub fn sort_lines_case_insensitive(
 7622        &mut self,
 7623        _: &SortLinesCaseInsensitive,
 7624        window: &mut Window,
 7625        cx: &mut Context<Self>,
 7626    ) {
 7627        self.manipulate_lines(window, cx, |lines| {
 7628            lines.sort_by_key(|line| line.to_lowercase())
 7629        })
 7630    }
 7631
 7632    pub fn unique_lines_case_insensitive(
 7633        &mut self,
 7634        _: &UniqueLinesCaseInsensitive,
 7635        window: &mut Window,
 7636        cx: &mut Context<Self>,
 7637    ) {
 7638        self.manipulate_lines(window, cx, |lines| {
 7639            let mut seen = HashSet::default();
 7640            lines.retain(|line| seen.insert(line.to_lowercase()));
 7641        })
 7642    }
 7643
 7644    pub fn unique_lines_case_sensitive(
 7645        &mut self,
 7646        _: &UniqueLinesCaseSensitive,
 7647        window: &mut Window,
 7648        cx: &mut Context<Self>,
 7649    ) {
 7650        self.manipulate_lines(window, cx, |lines| {
 7651            let mut seen = HashSet::default();
 7652            lines.retain(|line| seen.insert(*line));
 7653        })
 7654    }
 7655
 7656    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 7657        let Some(project) = self.project.clone() else {
 7658            return;
 7659        };
 7660        self.reload(project, window, cx)
 7661            .detach_and_notify_err(window, cx);
 7662    }
 7663
 7664    pub fn restore_file(
 7665        &mut self,
 7666        _: &::git::RestoreFile,
 7667        window: &mut Window,
 7668        cx: &mut Context<Self>,
 7669    ) {
 7670        let mut buffer_ids = HashSet::default();
 7671        let snapshot = self.buffer().read(cx).snapshot(cx);
 7672        for selection in self.selections.all::<usize>(cx) {
 7673            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 7674        }
 7675
 7676        let buffer = self.buffer().read(cx);
 7677        let ranges = buffer_ids
 7678            .into_iter()
 7679            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 7680            .collect::<Vec<_>>();
 7681
 7682        self.restore_hunks_in_ranges(ranges, window, cx);
 7683    }
 7684
 7685    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 7686        let selections = self
 7687            .selections
 7688            .all(cx)
 7689            .into_iter()
 7690            .map(|s| s.range())
 7691            .collect();
 7692        self.restore_hunks_in_ranges(selections, window, cx);
 7693    }
 7694
 7695    fn restore_hunks_in_ranges(
 7696        &mut self,
 7697        ranges: Vec<Range<Point>>,
 7698        window: &mut Window,
 7699        cx: &mut Context<Editor>,
 7700    ) {
 7701        let mut revert_changes = HashMap::default();
 7702        let snapshot = self.buffer.read(cx).snapshot(cx);
 7703        let Some(project) = &self.project else {
 7704            return;
 7705        };
 7706
 7707        let chunk_by = self
 7708            .snapshot(window, cx)
 7709            .hunks_for_ranges(ranges.into_iter())
 7710            .into_iter()
 7711            .chunk_by(|hunk| hunk.buffer_id);
 7712        for (buffer_id, hunks) in &chunk_by {
 7713            let hunks = hunks.collect::<Vec<_>>();
 7714            for hunk in &hunks {
 7715                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 7716            }
 7717            Self::do_stage_or_unstage(
 7718                project,
 7719                false,
 7720                buffer_id,
 7721                hunks.into_iter(),
 7722                &snapshot,
 7723                window,
 7724                cx,
 7725            );
 7726        }
 7727        drop(chunk_by);
 7728        if !revert_changes.is_empty() {
 7729            self.transact(window, cx, |editor, window, cx| {
 7730                editor.restore(revert_changes, window, cx);
 7731            });
 7732        }
 7733    }
 7734
 7735    pub fn open_active_item_in_terminal(
 7736        &mut self,
 7737        _: &OpenInTerminal,
 7738        window: &mut Window,
 7739        cx: &mut Context<Self>,
 7740    ) {
 7741        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 7742            let project_path = buffer.read(cx).project_path(cx)?;
 7743            let project = self.project.as_ref()?.read(cx);
 7744            let entry = project.entry_for_path(&project_path, cx)?;
 7745            let parent = match &entry.canonical_path {
 7746                Some(canonical_path) => canonical_path.to_path_buf(),
 7747                None => project.absolute_path(&project_path, cx)?,
 7748            }
 7749            .parent()?
 7750            .to_path_buf();
 7751            Some(parent)
 7752        }) {
 7753            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 7754        }
 7755    }
 7756
 7757    pub fn prepare_restore_change(
 7758        &self,
 7759        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 7760        hunk: &MultiBufferDiffHunk,
 7761        cx: &mut App,
 7762    ) -> Option<()> {
 7763        let buffer = self.buffer.read(cx);
 7764        let diff = buffer.diff_for(hunk.buffer_id)?;
 7765        let buffer = buffer.buffer(hunk.buffer_id)?;
 7766        let buffer = buffer.read(cx);
 7767        let original_text = diff
 7768            .read(cx)
 7769            .base_text()
 7770            .as_ref()?
 7771            .as_rope()
 7772            .slice(hunk.diff_base_byte_range.clone());
 7773        let buffer_snapshot = buffer.snapshot();
 7774        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 7775        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 7776            probe
 7777                .0
 7778                .start
 7779                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 7780                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 7781        }) {
 7782            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 7783            Some(())
 7784        } else {
 7785            None
 7786        }
 7787    }
 7788
 7789    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 7790        self.manipulate_lines(window, cx, |lines| lines.reverse())
 7791    }
 7792
 7793    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 7794        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 7795    }
 7796
 7797    fn manipulate_lines<Fn>(
 7798        &mut self,
 7799        window: &mut Window,
 7800        cx: &mut Context<Self>,
 7801        mut callback: Fn,
 7802    ) where
 7803        Fn: FnMut(&mut Vec<&str>),
 7804    {
 7805        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7806        let buffer = self.buffer.read(cx).snapshot(cx);
 7807
 7808        let mut edits = Vec::new();
 7809
 7810        let selections = self.selections.all::<Point>(cx);
 7811        let mut selections = selections.iter().peekable();
 7812        let mut contiguous_row_selections = Vec::new();
 7813        let mut new_selections = Vec::new();
 7814        let mut added_lines = 0;
 7815        let mut removed_lines = 0;
 7816
 7817        while let Some(selection) = selections.next() {
 7818            let (start_row, end_row) = consume_contiguous_rows(
 7819                &mut contiguous_row_selections,
 7820                selection,
 7821                &display_map,
 7822                &mut selections,
 7823            );
 7824
 7825            let start_point = Point::new(start_row.0, 0);
 7826            let end_point = Point::new(
 7827                end_row.previous_row().0,
 7828                buffer.line_len(end_row.previous_row()),
 7829            );
 7830            let text = buffer
 7831                .text_for_range(start_point..end_point)
 7832                .collect::<String>();
 7833
 7834            let mut lines = text.split('\n').collect_vec();
 7835
 7836            let lines_before = lines.len();
 7837            callback(&mut lines);
 7838            let lines_after = lines.len();
 7839
 7840            edits.push((start_point..end_point, lines.join("\n")));
 7841
 7842            // Selections must change based on added and removed line count
 7843            let start_row =
 7844                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 7845            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 7846            new_selections.push(Selection {
 7847                id: selection.id,
 7848                start: start_row,
 7849                end: end_row,
 7850                goal: SelectionGoal::None,
 7851                reversed: selection.reversed,
 7852            });
 7853
 7854            if lines_after > lines_before {
 7855                added_lines += lines_after - lines_before;
 7856            } else if lines_before > lines_after {
 7857                removed_lines += lines_before - lines_after;
 7858            }
 7859        }
 7860
 7861        self.transact(window, cx, |this, window, cx| {
 7862            let buffer = this.buffer.update(cx, |buffer, cx| {
 7863                buffer.edit(edits, None, cx);
 7864                buffer.snapshot(cx)
 7865            });
 7866
 7867            // Recalculate offsets on newly edited buffer
 7868            let new_selections = new_selections
 7869                .iter()
 7870                .map(|s| {
 7871                    let start_point = Point::new(s.start.0, 0);
 7872                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 7873                    Selection {
 7874                        id: s.id,
 7875                        start: buffer.point_to_offset(start_point),
 7876                        end: buffer.point_to_offset(end_point),
 7877                        goal: s.goal,
 7878                        reversed: s.reversed,
 7879                    }
 7880                })
 7881                .collect();
 7882
 7883            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 7884                s.select(new_selections);
 7885            });
 7886
 7887            this.request_autoscroll(Autoscroll::fit(), cx);
 7888        });
 7889    }
 7890
 7891    pub fn convert_to_upper_case(
 7892        &mut self,
 7893        _: &ConvertToUpperCase,
 7894        window: &mut Window,
 7895        cx: &mut Context<Self>,
 7896    ) {
 7897        self.manipulate_text(window, cx, |text| text.to_uppercase())
 7898    }
 7899
 7900    pub fn convert_to_lower_case(
 7901        &mut self,
 7902        _: &ConvertToLowerCase,
 7903        window: &mut Window,
 7904        cx: &mut Context<Self>,
 7905    ) {
 7906        self.manipulate_text(window, cx, |text| text.to_lowercase())
 7907    }
 7908
 7909    pub fn convert_to_title_case(
 7910        &mut self,
 7911        _: &ConvertToTitleCase,
 7912        window: &mut Window,
 7913        cx: &mut Context<Self>,
 7914    ) {
 7915        self.manipulate_text(window, cx, |text| {
 7916            text.split('\n')
 7917                .map(|line| line.to_case(Case::Title))
 7918                .join("\n")
 7919        })
 7920    }
 7921
 7922    pub fn convert_to_snake_case(
 7923        &mut self,
 7924        _: &ConvertToSnakeCase,
 7925        window: &mut Window,
 7926        cx: &mut Context<Self>,
 7927    ) {
 7928        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
 7929    }
 7930
 7931    pub fn convert_to_kebab_case(
 7932        &mut self,
 7933        _: &ConvertToKebabCase,
 7934        window: &mut Window,
 7935        cx: &mut Context<Self>,
 7936    ) {
 7937        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
 7938    }
 7939
 7940    pub fn convert_to_upper_camel_case(
 7941        &mut self,
 7942        _: &ConvertToUpperCamelCase,
 7943        window: &mut Window,
 7944        cx: &mut Context<Self>,
 7945    ) {
 7946        self.manipulate_text(window, cx, |text| {
 7947            text.split('\n')
 7948                .map(|line| line.to_case(Case::UpperCamel))
 7949                .join("\n")
 7950        })
 7951    }
 7952
 7953    pub fn convert_to_lower_camel_case(
 7954        &mut self,
 7955        _: &ConvertToLowerCamelCase,
 7956        window: &mut Window,
 7957        cx: &mut Context<Self>,
 7958    ) {
 7959        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
 7960    }
 7961
 7962    pub fn convert_to_opposite_case(
 7963        &mut self,
 7964        _: &ConvertToOppositeCase,
 7965        window: &mut Window,
 7966        cx: &mut Context<Self>,
 7967    ) {
 7968        self.manipulate_text(window, cx, |text| {
 7969            text.chars()
 7970                .fold(String::with_capacity(text.len()), |mut t, c| {
 7971                    if c.is_uppercase() {
 7972                        t.extend(c.to_lowercase());
 7973                    } else {
 7974                        t.extend(c.to_uppercase());
 7975                    }
 7976                    t
 7977                })
 7978        })
 7979    }
 7980
 7981    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
 7982    where
 7983        Fn: FnMut(&str) -> String,
 7984    {
 7985        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7986        let buffer = self.buffer.read(cx).snapshot(cx);
 7987
 7988        let mut new_selections = Vec::new();
 7989        let mut edits = Vec::new();
 7990        let mut selection_adjustment = 0i32;
 7991
 7992        for selection in self.selections.all::<usize>(cx) {
 7993            let selection_is_empty = selection.is_empty();
 7994
 7995            let (start, end) = if selection_is_empty {
 7996                let word_range = movement::surrounding_word(
 7997                    &display_map,
 7998                    selection.start.to_display_point(&display_map),
 7999                );
 8000                let start = word_range.start.to_offset(&display_map, Bias::Left);
 8001                let end = word_range.end.to_offset(&display_map, Bias::Left);
 8002                (start, end)
 8003            } else {
 8004                (selection.start, selection.end)
 8005            };
 8006
 8007            let text = buffer.text_for_range(start..end).collect::<String>();
 8008            let old_length = text.len() as i32;
 8009            let text = callback(&text);
 8010
 8011            new_selections.push(Selection {
 8012                start: (start as i32 - selection_adjustment) as usize,
 8013                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
 8014                goal: SelectionGoal::None,
 8015                ..selection
 8016            });
 8017
 8018            selection_adjustment += old_length - text.len() as i32;
 8019
 8020            edits.push((start..end, text));
 8021        }
 8022
 8023        self.transact(window, cx, |this, window, cx| {
 8024            this.buffer.update(cx, |buffer, cx| {
 8025                buffer.edit(edits, None, cx);
 8026            });
 8027
 8028            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8029                s.select(new_selections);
 8030            });
 8031
 8032            this.request_autoscroll(Autoscroll::fit(), cx);
 8033        });
 8034    }
 8035
 8036    pub fn duplicate(
 8037        &mut self,
 8038        upwards: bool,
 8039        whole_lines: bool,
 8040        window: &mut Window,
 8041        cx: &mut Context<Self>,
 8042    ) {
 8043        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8044        let buffer = &display_map.buffer_snapshot;
 8045        let selections = self.selections.all::<Point>(cx);
 8046
 8047        let mut edits = Vec::new();
 8048        let mut selections_iter = selections.iter().peekable();
 8049        while let Some(selection) = selections_iter.next() {
 8050            let mut rows = selection.spanned_rows(false, &display_map);
 8051            // duplicate line-wise
 8052            if whole_lines || selection.start == selection.end {
 8053                // Avoid duplicating the same lines twice.
 8054                while let Some(next_selection) = selections_iter.peek() {
 8055                    let next_rows = next_selection.spanned_rows(false, &display_map);
 8056                    if next_rows.start < rows.end {
 8057                        rows.end = next_rows.end;
 8058                        selections_iter.next().unwrap();
 8059                    } else {
 8060                        break;
 8061                    }
 8062                }
 8063
 8064                // Copy the text from the selected row region and splice it either at the start
 8065                // or end of the region.
 8066                let start = Point::new(rows.start.0, 0);
 8067                let end = Point::new(
 8068                    rows.end.previous_row().0,
 8069                    buffer.line_len(rows.end.previous_row()),
 8070                );
 8071                let text = buffer
 8072                    .text_for_range(start..end)
 8073                    .chain(Some("\n"))
 8074                    .collect::<String>();
 8075                let insert_location = if upwards {
 8076                    Point::new(rows.end.0, 0)
 8077                } else {
 8078                    start
 8079                };
 8080                edits.push((insert_location..insert_location, text));
 8081            } else {
 8082                // duplicate character-wise
 8083                let start = selection.start;
 8084                let end = selection.end;
 8085                let text = buffer.text_for_range(start..end).collect::<String>();
 8086                edits.push((selection.end..selection.end, text));
 8087            }
 8088        }
 8089
 8090        self.transact(window, cx, |this, _, cx| {
 8091            this.buffer.update(cx, |buffer, cx| {
 8092                buffer.edit(edits, None, cx);
 8093            });
 8094
 8095            this.request_autoscroll(Autoscroll::fit(), cx);
 8096        });
 8097    }
 8098
 8099    pub fn duplicate_line_up(
 8100        &mut self,
 8101        _: &DuplicateLineUp,
 8102        window: &mut Window,
 8103        cx: &mut Context<Self>,
 8104    ) {
 8105        self.duplicate(true, true, window, cx);
 8106    }
 8107
 8108    pub fn duplicate_line_down(
 8109        &mut self,
 8110        _: &DuplicateLineDown,
 8111        window: &mut Window,
 8112        cx: &mut Context<Self>,
 8113    ) {
 8114        self.duplicate(false, true, window, cx);
 8115    }
 8116
 8117    pub fn duplicate_selection(
 8118        &mut self,
 8119        _: &DuplicateSelection,
 8120        window: &mut Window,
 8121        cx: &mut Context<Self>,
 8122    ) {
 8123        self.duplicate(false, false, window, cx);
 8124    }
 8125
 8126    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
 8127        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8128        let buffer = self.buffer.read(cx).snapshot(cx);
 8129
 8130        let mut edits = Vec::new();
 8131        let mut unfold_ranges = Vec::new();
 8132        let mut refold_creases = Vec::new();
 8133
 8134        let selections = self.selections.all::<Point>(cx);
 8135        let mut selections = selections.iter().peekable();
 8136        let mut contiguous_row_selections = Vec::new();
 8137        let mut new_selections = Vec::new();
 8138
 8139        while let Some(selection) = selections.next() {
 8140            // Find all the selections that span a contiguous row range
 8141            let (start_row, end_row) = consume_contiguous_rows(
 8142                &mut contiguous_row_selections,
 8143                selection,
 8144                &display_map,
 8145                &mut selections,
 8146            );
 8147
 8148            // Move the text spanned by the row range to be before the line preceding the row range
 8149            if start_row.0 > 0 {
 8150                let range_to_move = Point::new(
 8151                    start_row.previous_row().0,
 8152                    buffer.line_len(start_row.previous_row()),
 8153                )
 8154                    ..Point::new(
 8155                        end_row.previous_row().0,
 8156                        buffer.line_len(end_row.previous_row()),
 8157                    );
 8158                let insertion_point = display_map
 8159                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
 8160                    .0;
 8161
 8162                // Don't move lines across excerpts
 8163                if buffer
 8164                    .excerpt_containing(insertion_point..range_to_move.end)
 8165                    .is_some()
 8166                {
 8167                    let text = buffer
 8168                        .text_for_range(range_to_move.clone())
 8169                        .flat_map(|s| s.chars())
 8170                        .skip(1)
 8171                        .chain(['\n'])
 8172                        .collect::<String>();
 8173
 8174                    edits.push((
 8175                        buffer.anchor_after(range_to_move.start)
 8176                            ..buffer.anchor_before(range_to_move.end),
 8177                        String::new(),
 8178                    ));
 8179                    let insertion_anchor = buffer.anchor_after(insertion_point);
 8180                    edits.push((insertion_anchor..insertion_anchor, text));
 8181
 8182                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
 8183
 8184                    // Move selections up
 8185                    new_selections.extend(contiguous_row_selections.drain(..).map(
 8186                        |mut selection| {
 8187                            selection.start.row -= row_delta;
 8188                            selection.end.row -= row_delta;
 8189                            selection
 8190                        },
 8191                    ));
 8192
 8193                    // Move folds up
 8194                    unfold_ranges.push(range_to_move.clone());
 8195                    for fold in display_map.folds_in_range(
 8196                        buffer.anchor_before(range_to_move.start)
 8197                            ..buffer.anchor_after(range_to_move.end),
 8198                    ) {
 8199                        let mut start = fold.range.start.to_point(&buffer);
 8200                        let mut end = fold.range.end.to_point(&buffer);
 8201                        start.row -= row_delta;
 8202                        end.row -= row_delta;
 8203                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
 8204                    }
 8205                }
 8206            }
 8207
 8208            // If we didn't move line(s), preserve the existing selections
 8209            new_selections.append(&mut contiguous_row_selections);
 8210        }
 8211
 8212        self.transact(window, cx, |this, window, cx| {
 8213            this.unfold_ranges(&unfold_ranges, true, true, cx);
 8214            this.buffer.update(cx, |buffer, cx| {
 8215                for (range, text) in edits {
 8216                    buffer.edit([(range, text)], None, cx);
 8217                }
 8218            });
 8219            this.fold_creases(refold_creases, true, window, cx);
 8220            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8221                s.select(new_selections);
 8222            })
 8223        });
 8224    }
 8225
 8226    pub fn move_line_down(
 8227        &mut self,
 8228        _: &MoveLineDown,
 8229        window: &mut Window,
 8230        cx: &mut Context<Self>,
 8231    ) {
 8232        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8233        let buffer = self.buffer.read(cx).snapshot(cx);
 8234
 8235        let mut edits = Vec::new();
 8236        let mut unfold_ranges = Vec::new();
 8237        let mut refold_creases = Vec::new();
 8238
 8239        let selections = self.selections.all::<Point>(cx);
 8240        let mut selections = selections.iter().peekable();
 8241        let mut contiguous_row_selections = Vec::new();
 8242        let mut new_selections = Vec::new();
 8243
 8244        while let Some(selection) = selections.next() {
 8245            // Find all the selections that span a contiguous row range
 8246            let (start_row, end_row) = consume_contiguous_rows(
 8247                &mut contiguous_row_selections,
 8248                selection,
 8249                &display_map,
 8250                &mut selections,
 8251            );
 8252
 8253            // Move the text spanned by the row range to be after the last line of the row range
 8254            if end_row.0 <= buffer.max_point().row {
 8255                let range_to_move =
 8256                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
 8257                let insertion_point = display_map
 8258                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
 8259                    .0;
 8260
 8261                // Don't move lines across excerpt boundaries
 8262                if buffer
 8263                    .excerpt_containing(range_to_move.start..insertion_point)
 8264                    .is_some()
 8265                {
 8266                    let mut text = String::from("\n");
 8267                    text.extend(buffer.text_for_range(range_to_move.clone()));
 8268                    text.pop(); // Drop trailing newline
 8269                    edits.push((
 8270                        buffer.anchor_after(range_to_move.start)
 8271                            ..buffer.anchor_before(range_to_move.end),
 8272                        String::new(),
 8273                    ));
 8274                    let insertion_anchor = buffer.anchor_after(insertion_point);
 8275                    edits.push((insertion_anchor..insertion_anchor, text));
 8276
 8277                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
 8278
 8279                    // Move selections down
 8280                    new_selections.extend(contiguous_row_selections.drain(..).map(
 8281                        |mut selection| {
 8282                            selection.start.row += row_delta;
 8283                            selection.end.row += row_delta;
 8284                            selection
 8285                        },
 8286                    ));
 8287
 8288                    // Move folds down
 8289                    unfold_ranges.push(range_to_move.clone());
 8290                    for fold in display_map.folds_in_range(
 8291                        buffer.anchor_before(range_to_move.start)
 8292                            ..buffer.anchor_after(range_to_move.end),
 8293                    ) {
 8294                        let mut start = fold.range.start.to_point(&buffer);
 8295                        let mut end = fold.range.end.to_point(&buffer);
 8296                        start.row += row_delta;
 8297                        end.row += row_delta;
 8298                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
 8299                    }
 8300                }
 8301            }
 8302
 8303            // If we didn't move line(s), preserve the existing selections
 8304            new_selections.append(&mut contiguous_row_selections);
 8305        }
 8306
 8307        self.transact(window, cx, |this, window, cx| {
 8308            this.unfold_ranges(&unfold_ranges, true, true, cx);
 8309            this.buffer.update(cx, |buffer, cx| {
 8310                for (range, text) in edits {
 8311                    buffer.edit([(range, text)], None, cx);
 8312                }
 8313            });
 8314            this.fold_creases(refold_creases, true, window, cx);
 8315            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8316                s.select(new_selections)
 8317            });
 8318        });
 8319    }
 8320
 8321    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
 8322        let text_layout_details = &self.text_layout_details(window);
 8323        self.transact(window, cx, |this, window, cx| {
 8324            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8325                let mut edits: Vec<(Range<usize>, String)> = Default::default();
 8326                let line_mode = s.line_mode;
 8327                s.move_with(|display_map, selection| {
 8328                    if !selection.is_empty() || line_mode {
 8329                        return;
 8330                    }
 8331
 8332                    let mut head = selection.head();
 8333                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
 8334                    if head.column() == display_map.line_len(head.row()) {
 8335                        transpose_offset = display_map
 8336                            .buffer_snapshot
 8337                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 8338                    }
 8339
 8340                    if transpose_offset == 0 {
 8341                        return;
 8342                    }
 8343
 8344                    *head.column_mut() += 1;
 8345                    head = display_map.clip_point(head, Bias::Right);
 8346                    let goal = SelectionGoal::HorizontalPosition(
 8347                        display_map
 8348                            .x_for_display_point(head, text_layout_details)
 8349                            .into(),
 8350                    );
 8351                    selection.collapse_to(head, goal);
 8352
 8353                    let transpose_start = display_map
 8354                        .buffer_snapshot
 8355                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 8356                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
 8357                        let transpose_end = display_map
 8358                            .buffer_snapshot
 8359                            .clip_offset(transpose_offset + 1, Bias::Right);
 8360                        if let Some(ch) =
 8361                            display_map.buffer_snapshot.chars_at(transpose_start).next()
 8362                        {
 8363                            edits.push((transpose_start..transpose_offset, String::new()));
 8364                            edits.push((transpose_end..transpose_end, ch.to_string()));
 8365                        }
 8366                    }
 8367                });
 8368                edits
 8369            });
 8370            this.buffer
 8371                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 8372            let selections = this.selections.all::<usize>(cx);
 8373            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8374                s.select(selections);
 8375            });
 8376        });
 8377    }
 8378
 8379    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
 8380        self.rewrap_impl(IsVimMode::No, cx)
 8381    }
 8382
 8383    pub fn rewrap_impl(&mut self, is_vim_mode: IsVimMode, cx: &mut Context<Self>) {
 8384        let buffer = self.buffer.read(cx).snapshot(cx);
 8385        let selections = self.selections.all::<Point>(cx);
 8386        let mut selections = selections.iter().peekable();
 8387
 8388        let mut edits = Vec::new();
 8389        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
 8390
 8391        while let Some(selection) = selections.next() {
 8392            let mut start_row = selection.start.row;
 8393            let mut end_row = selection.end.row;
 8394
 8395            // Skip selections that overlap with a range that has already been rewrapped.
 8396            let selection_range = start_row..end_row;
 8397            if rewrapped_row_ranges
 8398                .iter()
 8399                .any(|range| range.overlaps(&selection_range))
 8400            {
 8401                continue;
 8402            }
 8403
 8404            let tab_size = buffer.settings_at(selection.head(), cx).tab_size;
 8405
 8406            // Since not all lines in the selection may be at the same indent
 8407            // level, choose the indent size that is the most common between all
 8408            // of the lines.
 8409            //
 8410            // If there is a tie, we use the deepest indent.
 8411            let (indent_size, indent_end) = {
 8412                let mut indent_size_occurrences = HashMap::default();
 8413                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
 8414
 8415                for row in start_row..=end_row {
 8416                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
 8417                    rows_by_indent_size.entry(indent).or_default().push(row);
 8418                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
 8419                }
 8420
 8421                let indent_size = indent_size_occurrences
 8422                    .into_iter()
 8423                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
 8424                    .map(|(indent, _)| indent)
 8425                    .unwrap_or_default();
 8426                let row = rows_by_indent_size[&indent_size][0];
 8427                let indent_end = Point::new(row, indent_size.len);
 8428
 8429                (indent_size, indent_end)
 8430            };
 8431
 8432            let mut line_prefix = indent_size.chars().collect::<String>();
 8433
 8434            let mut inside_comment = false;
 8435            if let Some(comment_prefix) =
 8436                buffer
 8437                    .language_scope_at(selection.head())
 8438                    .and_then(|language| {
 8439                        language
 8440                            .line_comment_prefixes()
 8441                            .iter()
 8442                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
 8443                            .cloned()
 8444                    })
 8445            {
 8446                line_prefix.push_str(&comment_prefix);
 8447                inside_comment = true;
 8448            }
 8449
 8450            let language_settings = buffer.settings_at(selection.head(), cx);
 8451            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
 8452                RewrapBehavior::InComments => inside_comment,
 8453                RewrapBehavior::InSelections => !selection.is_empty(),
 8454                RewrapBehavior::Anywhere => true,
 8455            };
 8456
 8457            let should_rewrap = is_vim_mode == IsVimMode::Yes || allow_rewrap_based_on_language;
 8458            if !should_rewrap {
 8459                continue;
 8460            }
 8461
 8462            if selection.is_empty() {
 8463                'expand_upwards: while start_row > 0 {
 8464                    let prev_row = start_row - 1;
 8465                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
 8466                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
 8467                    {
 8468                        start_row = prev_row;
 8469                    } else {
 8470                        break 'expand_upwards;
 8471                    }
 8472                }
 8473
 8474                'expand_downwards: while end_row < buffer.max_point().row {
 8475                    let next_row = end_row + 1;
 8476                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
 8477                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
 8478                    {
 8479                        end_row = next_row;
 8480                    } else {
 8481                        break 'expand_downwards;
 8482                    }
 8483                }
 8484            }
 8485
 8486            let start = Point::new(start_row, 0);
 8487            let start_offset = start.to_offset(&buffer);
 8488            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
 8489            let selection_text = buffer.text_for_range(start..end).collect::<String>();
 8490            let Some(lines_without_prefixes) = selection_text
 8491                .lines()
 8492                .map(|line| {
 8493                    line.strip_prefix(&line_prefix)
 8494                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
 8495                        .ok_or_else(|| {
 8496                            anyhow!("line did not start with prefix {line_prefix:?}: {line:?}")
 8497                        })
 8498                })
 8499                .collect::<Result<Vec<_>, _>>()
 8500                .log_err()
 8501            else {
 8502                continue;
 8503            };
 8504
 8505            let wrap_column = buffer
 8506                .settings_at(Point::new(start_row, 0), cx)
 8507                .preferred_line_length as usize;
 8508            let wrapped_text = wrap_with_prefix(
 8509                line_prefix,
 8510                lines_without_prefixes.join(" "),
 8511                wrap_column,
 8512                tab_size,
 8513            );
 8514
 8515            // TODO: should always use char-based diff while still supporting cursor behavior that
 8516            // matches vim.
 8517            let mut diff_options = DiffOptions::default();
 8518            if is_vim_mode == IsVimMode::Yes {
 8519                diff_options.max_word_diff_len = 0;
 8520                diff_options.max_word_diff_line_count = 0;
 8521            } else {
 8522                diff_options.max_word_diff_len = usize::MAX;
 8523                diff_options.max_word_diff_line_count = usize::MAX;
 8524            }
 8525
 8526            for (old_range, new_text) in
 8527                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
 8528            {
 8529                let edit_start = buffer.anchor_after(start_offset + old_range.start);
 8530                let edit_end = buffer.anchor_after(start_offset + old_range.end);
 8531                edits.push((edit_start..edit_end, new_text));
 8532            }
 8533
 8534            rewrapped_row_ranges.push(start_row..=end_row);
 8535        }
 8536
 8537        self.buffer
 8538            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 8539    }
 8540
 8541    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
 8542        let mut text = String::new();
 8543        let buffer = self.buffer.read(cx).snapshot(cx);
 8544        let mut selections = self.selections.all::<Point>(cx);
 8545        let mut clipboard_selections = Vec::with_capacity(selections.len());
 8546        {
 8547            let max_point = buffer.max_point();
 8548            let mut is_first = true;
 8549            for selection in &mut selections {
 8550                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 8551                if is_entire_line {
 8552                    selection.start = Point::new(selection.start.row, 0);
 8553                    if !selection.is_empty() && selection.end.column == 0 {
 8554                        selection.end = cmp::min(max_point, selection.end);
 8555                    } else {
 8556                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
 8557                    }
 8558                    selection.goal = SelectionGoal::None;
 8559                }
 8560                if is_first {
 8561                    is_first = false;
 8562                } else {
 8563                    text += "\n";
 8564                }
 8565                let mut len = 0;
 8566                for chunk in buffer.text_for_range(selection.start..selection.end) {
 8567                    text.push_str(chunk);
 8568                    len += chunk.len();
 8569                }
 8570                clipboard_selections.push(ClipboardSelection {
 8571                    len,
 8572                    is_entire_line,
 8573                    start_column: selection.start.column,
 8574                });
 8575            }
 8576        }
 8577
 8578        self.transact(window, cx, |this, window, cx| {
 8579            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8580                s.select(selections);
 8581            });
 8582            this.insert("", window, cx);
 8583        });
 8584        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
 8585    }
 8586
 8587    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
 8588        let item = self.cut_common(window, cx);
 8589        cx.write_to_clipboard(item);
 8590    }
 8591
 8592    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
 8593        self.change_selections(None, window, cx, |s| {
 8594            s.move_with(|snapshot, sel| {
 8595                if sel.is_empty() {
 8596                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
 8597                }
 8598            });
 8599        });
 8600        let item = self.cut_common(window, cx);
 8601        cx.set_global(KillRing(item))
 8602    }
 8603
 8604    pub fn kill_ring_yank(
 8605        &mut self,
 8606        _: &KillRingYank,
 8607        window: &mut Window,
 8608        cx: &mut Context<Self>,
 8609    ) {
 8610        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
 8611            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
 8612                (kill_ring.text().to_string(), kill_ring.metadata_json())
 8613            } else {
 8614                return;
 8615            }
 8616        } else {
 8617            return;
 8618        };
 8619        self.do_paste(&text, metadata, false, window, cx);
 8620    }
 8621
 8622    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
 8623        let selections = self.selections.all::<Point>(cx);
 8624        let buffer = self.buffer.read(cx).read(cx);
 8625        let mut text = String::new();
 8626
 8627        let mut clipboard_selections = Vec::with_capacity(selections.len());
 8628        {
 8629            let max_point = buffer.max_point();
 8630            let mut is_first = true;
 8631            for selection in selections.iter() {
 8632                let mut start = selection.start;
 8633                let mut end = selection.end;
 8634                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 8635                if is_entire_line {
 8636                    start = Point::new(start.row, 0);
 8637                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
 8638                }
 8639                if is_first {
 8640                    is_first = false;
 8641                } else {
 8642                    text += "\n";
 8643                }
 8644                let mut len = 0;
 8645                for chunk in buffer.text_for_range(start..end) {
 8646                    text.push_str(chunk);
 8647                    len += chunk.len();
 8648                }
 8649                clipboard_selections.push(ClipboardSelection {
 8650                    len,
 8651                    is_entire_line,
 8652                    start_column: start.column,
 8653                });
 8654            }
 8655        }
 8656
 8657        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
 8658            text,
 8659            clipboard_selections,
 8660        ));
 8661    }
 8662
 8663    pub fn do_paste(
 8664        &mut self,
 8665        text: &String,
 8666        clipboard_selections: Option<Vec<ClipboardSelection>>,
 8667        handle_entire_lines: bool,
 8668        window: &mut Window,
 8669        cx: &mut Context<Self>,
 8670    ) {
 8671        if self.read_only(cx) {
 8672            return;
 8673        }
 8674
 8675        let clipboard_text = Cow::Borrowed(text);
 8676
 8677        self.transact(window, cx, |this, window, cx| {
 8678            if let Some(mut clipboard_selections) = clipboard_selections {
 8679                let old_selections = this.selections.all::<usize>(cx);
 8680                let all_selections_were_entire_line =
 8681                    clipboard_selections.iter().all(|s| s.is_entire_line);
 8682                let first_selection_start_column =
 8683                    clipboard_selections.first().map(|s| s.start_column);
 8684                if clipboard_selections.len() != old_selections.len() {
 8685                    clipboard_selections.drain(..);
 8686                }
 8687                let cursor_offset = this.selections.last::<usize>(cx).head();
 8688                let mut auto_indent_on_paste = true;
 8689
 8690                this.buffer.update(cx, |buffer, cx| {
 8691                    let snapshot = buffer.read(cx);
 8692                    auto_indent_on_paste =
 8693                        snapshot.settings_at(cursor_offset, cx).auto_indent_on_paste;
 8694
 8695                    let mut start_offset = 0;
 8696                    let mut edits = Vec::new();
 8697                    let mut original_start_columns = Vec::new();
 8698                    for (ix, selection) in old_selections.iter().enumerate() {
 8699                        let to_insert;
 8700                        let entire_line;
 8701                        let original_start_column;
 8702                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
 8703                            let end_offset = start_offset + clipboard_selection.len;
 8704                            to_insert = &clipboard_text[start_offset..end_offset];
 8705                            entire_line = clipboard_selection.is_entire_line;
 8706                            start_offset = end_offset + 1;
 8707                            original_start_column = Some(clipboard_selection.start_column);
 8708                        } else {
 8709                            to_insert = clipboard_text.as_str();
 8710                            entire_line = all_selections_were_entire_line;
 8711                            original_start_column = first_selection_start_column
 8712                        }
 8713
 8714                        // If the corresponding selection was empty when this slice of the
 8715                        // clipboard text was written, then the entire line containing the
 8716                        // selection was copied. If this selection is also currently empty,
 8717                        // then paste the line before the current line of the buffer.
 8718                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
 8719                            let column = selection.start.to_point(&snapshot).column as usize;
 8720                            let line_start = selection.start - column;
 8721                            line_start..line_start
 8722                        } else {
 8723                            selection.range()
 8724                        };
 8725
 8726                        edits.push((range, to_insert));
 8727                        original_start_columns.extend(original_start_column);
 8728                    }
 8729                    drop(snapshot);
 8730
 8731                    buffer.edit(
 8732                        edits,
 8733                        if auto_indent_on_paste {
 8734                            Some(AutoindentMode::Block {
 8735                                original_start_columns,
 8736                            })
 8737                        } else {
 8738                            None
 8739                        },
 8740                        cx,
 8741                    );
 8742                });
 8743
 8744                let selections = this.selections.all::<usize>(cx);
 8745                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8746                    s.select(selections)
 8747                });
 8748            } else {
 8749                this.insert(&clipboard_text, window, cx);
 8750            }
 8751        });
 8752    }
 8753
 8754    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
 8755        if let Some(item) = cx.read_from_clipboard() {
 8756            let entries = item.entries();
 8757
 8758            match entries.first() {
 8759                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
 8760                // of all the pasted entries.
 8761                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
 8762                    .do_paste(
 8763                        clipboard_string.text(),
 8764                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
 8765                        true,
 8766                        window,
 8767                        cx,
 8768                    ),
 8769                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
 8770            }
 8771        }
 8772    }
 8773
 8774    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
 8775        if self.read_only(cx) {
 8776            return;
 8777        }
 8778
 8779        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
 8780            if let Some((selections, _)) =
 8781                self.selection_history.transaction(transaction_id).cloned()
 8782            {
 8783                self.change_selections(None, window, cx, |s| {
 8784                    s.select_anchors(selections.to_vec());
 8785                });
 8786            } else {
 8787                log::error!(
 8788                    "No entry in selection_history found for undo. \
 8789                     This may correspond to a bug where undo does not update the selection. \
 8790                     If this is occurring, please add details to \
 8791                     https://github.com/zed-industries/zed/issues/22692"
 8792                );
 8793            }
 8794            self.request_autoscroll(Autoscroll::fit(), cx);
 8795            self.unmark_text(window, cx);
 8796            self.refresh_inline_completion(true, false, window, cx);
 8797            cx.emit(EditorEvent::Edited { transaction_id });
 8798            cx.emit(EditorEvent::TransactionUndone { transaction_id });
 8799        }
 8800    }
 8801
 8802    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
 8803        if self.read_only(cx) {
 8804            return;
 8805        }
 8806
 8807        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
 8808            if let Some((_, Some(selections))) =
 8809                self.selection_history.transaction(transaction_id).cloned()
 8810            {
 8811                self.change_selections(None, window, cx, |s| {
 8812                    s.select_anchors(selections.to_vec());
 8813                });
 8814            } else {
 8815                log::error!(
 8816                    "No entry in selection_history found for redo. \
 8817                     This may correspond to a bug where undo does not update the selection. \
 8818                     If this is occurring, please add details to \
 8819                     https://github.com/zed-industries/zed/issues/22692"
 8820                );
 8821            }
 8822            self.request_autoscroll(Autoscroll::fit(), cx);
 8823            self.unmark_text(window, cx);
 8824            self.refresh_inline_completion(true, false, window, cx);
 8825            cx.emit(EditorEvent::Edited { transaction_id });
 8826        }
 8827    }
 8828
 8829    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
 8830        self.buffer
 8831            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
 8832    }
 8833
 8834    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
 8835        self.buffer
 8836            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
 8837    }
 8838
 8839    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
 8840        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8841            let line_mode = s.line_mode;
 8842            s.move_with(|map, selection| {
 8843                let cursor = if selection.is_empty() && !line_mode {
 8844                    movement::left(map, selection.start)
 8845                } else {
 8846                    selection.start
 8847                };
 8848                selection.collapse_to(cursor, SelectionGoal::None);
 8849            });
 8850        })
 8851    }
 8852
 8853    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
 8854        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8855            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
 8856        })
 8857    }
 8858
 8859    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
 8860        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8861            let line_mode = s.line_mode;
 8862            s.move_with(|map, selection| {
 8863                let cursor = if selection.is_empty() && !line_mode {
 8864                    movement::right(map, selection.end)
 8865                } else {
 8866                    selection.end
 8867                };
 8868                selection.collapse_to(cursor, SelectionGoal::None)
 8869            });
 8870        })
 8871    }
 8872
 8873    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
 8874        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8875            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
 8876        })
 8877    }
 8878
 8879    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
 8880        if self.take_rename(true, window, cx).is_some() {
 8881            return;
 8882        }
 8883
 8884        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 8885            cx.propagate();
 8886            return;
 8887        }
 8888
 8889        let text_layout_details = &self.text_layout_details(window);
 8890        let selection_count = self.selections.count();
 8891        let first_selection = self.selections.first_anchor();
 8892
 8893        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8894            let line_mode = s.line_mode;
 8895            s.move_with(|map, selection| {
 8896                if !selection.is_empty() && !line_mode {
 8897                    selection.goal = SelectionGoal::None;
 8898                }
 8899                let (cursor, goal) = movement::up(
 8900                    map,
 8901                    selection.start,
 8902                    selection.goal,
 8903                    false,
 8904                    text_layout_details,
 8905                );
 8906                selection.collapse_to(cursor, goal);
 8907            });
 8908        });
 8909
 8910        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
 8911        {
 8912            cx.propagate();
 8913        }
 8914    }
 8915
 8916    pub fn move_up_by_lines(
 8917        &mut self,
 8918        action: &MoveUpByLines,
 8919        window: &mut Window,
 8920        cx: &mut Context<Self>,
 8921    ) {
 8922        if self.take_rename(true, window, cx).is_some() {
 8923            return;
 8924        }
 8925
 8926        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 8927            cx.propagate();
 8928            return;
 8929        }
 8930
 8931        let text_layout_details = &self.text_layout_details(window);
 8932
 8933        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8934            let line_mode = s.line_mode;
 8935            s.move_with(|map, selection| {
 8936                if !selection.is_empty() && !line_mode {
 8937                    selection.goal = SelectionGoal::None;
 8938                }
 8939                let (cursor, goal) = movement::up_by_rows(
 8940                    map,
 8941                    selection.start,
 8942                    action.lines,
 8943                    selection.goal,
 8944                    false,
 8945                    text_layout_details,
 8946                );
 8947                selection.collapse_to(cursor, goal);
 8948            });
 8949        })
 8950    }
 8951
 8952    pub fn move_down_by_lines(
 8953        &mut self,
 8954        action: &MoveDownByLines,
 8955        window: &mut Window,
 8956        cx: &mut Context<Self>,
 8957    ) {
 8958        if self.take_rename(true, window, cx).is_some() {
 8959            return;
 8960        }
 8961
 8962        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 8963            cx.propagate();
 8964            return;
 8965        }
 8966
 8967        let text_layout_details = &self.text_layout_details(window);
 8968
 8969        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8970            let line_mode = s.line_mode;
 8971            s.move_with(|map, selection| {
 8972                if !selection.is_empty() && !line_mode {
 8973                    selection.goal = SelectionGoal::None;
 8974                }
 8975                let (cursor, goal) = movement::down_by_rows(
 8976                    map,
 8977                    selection.start,
 8978                    action.lines,
 8979                    selection.goal,
 8980                    false,
 8981                    text_layout_details,
 8982                );
 8983                selection.collapse_to(cursor, goal);
 8984            });
 8985        })
 8986    }
 8987
 8988    pub fn select_down_by_lines(
 8989        &mut self,
 8990        action: &SelectDownByLines,
 8991        window: &mut Window,
 8992        cx: &mut Context<Self>,
 8993    ) {
 8994        let text_layout_details = &self.text_layout_details(window);
 8995        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8996            s.move_heads_with(|map, head, goal| {
 8997                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
 8998            })
 8999        })
 9000    }
 9001
 9002    pub fn select_up_by_lines(
 9003        &mut self,
 9004        action: &SelectUpByLines,
 9005        window: &mut Window,
 9006        cx: &mut Context<Self>,
 9007    ) {
 9008        let text_layout_details = &self.text_layout_details(window);
 9009        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9010            s.move_heads_with(|map, head, goal| {
 9011                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
 9012            })
 9013        })
 9014    }
 9015
 9016    pub fn select_page_up(
 9017        &mut self,
 9018        _: &SelectPageUp,
 9019        window: &mut Window,
 9020        cx: &mut Context<Self>,
 9021    ) {
 9022        let Some(row_count) = self.visible_row_count() else {
 9023            return;
 9024        };
 9025
 9026        let text_layout_details = &self.text_layout_details(window);
 9027
 9028        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9029            s.move_heads_with(|map, head, goal| {
 9030                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
 9031            })
 9032        })
 9033    }
 9034
 9035    pub fn move_page_up(
 9036        &mut self,
 9037        action: &MovePageUp,
 9038        window: &mut Window,
 9039        cx: &mut Context<Self>,
 9040    ) {
 9041        if self.take_rename(true, window, cx).is_some() {
 9042            return;
 9043        }
 9044
 9045        if self
 9046            .context_menu
 9047            .borrow_mut()
 9048            .as_mut()
 9049            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
 9050            .unwrap_or(false)
 9051        {
 9052            return;
 9053        }
 9054
 9055        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9056            cx.propagate();
 9057            return;
 9058        }
 9059
 9060        let Some(row_count) = self.visible_row_count() else {
 9061            return;
 9062        };
 9063
 9064        let autoscroll = if action.center_cursor {
 9065            Autoscroll::center()
 9066        } else {
 9067            Autoscroll::fit()
 9068        };
 9069
 9070        let text_layout_details = &self.text_layout_details(window);
 9071
 9072        self.change_selections(Some(autoscroll), window, cx, |s| {
 9073            let line_mode = s.line_mode;
 9074            s.move_with(|map, selection| {
 9075                if !selection.is_empty() && !line_mode {
 9076                    selection.goal = SelectionGoal::None;
 9077                }
 9078                let (cursor, goal) = movement::up_by_rows(
 9079                    map,
 9080                    selection.end,
 9081                    row_count,
 9082                    selection.goal,
 9083                    false,
 9084                    text_layout_details,
 9085                );
 9086                selection.collapse_to(cursor, goal);
 9087            });
 9088        });
 9089    }
 9090
 9091    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
 9092        let text_layout_details = &self.text_layout_details(window);
 9093        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9094            s.move_heads_with(|map, head, goal| {
 9095                movement::up(map, head, goal, false, text_layout_details)
 9096            })
 9097        })
 9098    }
 9099
 9100    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
 9101        self.take_rename(true, window, cx);
 9102
 9103        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9104            cx.propagate();
 9105            return;
 9106        }
 9107
 9108        let text_layout_details = &self.text_layout_details(window);
 9109        let selection_count = self.selections.count();
 9110        let first_selection = self.selections.first_anchor();
 9111
 9112        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9113            let line_mode = s.line_mode;
 9114            s.move_with(|map, selection| {
 9115                if !selection.is_empty() && !line_mode {
 9116                    selection.goal = SelectionGoal::None;
 9117                }
 9118                let (cursor, goal) = movement::down(
 9119                    map,
 9120                    selection.end,
 9121                    selection.goal,
 9122                    false,
 9123                    text_layout_details,
 9124                );
 9125                selection.collapse_to(cursor, goal);
 9126            });
 9127        });
 9128
 9129        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
 9130        {
 9131            cx.propagate();
 9132        }
 9133    }
 9134
 9135    pub fn select_page_down(
 9136        &mut self,
 9137        _: &SelectPageDown,
 9138        window: &mut Window,
 9139        cx: &mut Context<Self>,
 9140    ) {
 9141        let Some(row_count) = self.visible_row_count() else {
 9142            return;
 9143        };
 9144
 9145        let text_layout_details = &self.text_layout_details(window);
 9146
 9147        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9148            s.move_heads_with(|map, head, goal| {
 9149                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
 9150            })
 9151        })
 9152    }
 9153
 9154    pub fn move_page_down(
 9155        &mut self,
 9156        action: &MovePageDown,
 9157        window: &mut Window,
 9158        cx: &mut Context<Self>,
 9159    ) {
 9160        if self.take_rename(true, window, cx).is_some() {
 9161            return;
 9162        }
 9163
 9164        if self
 9165            .context_menu
 9166            .borrow_mut()
 9167            .as_mut()
 9168            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
 9169            .unwrap_or(false)
 9170        {
 9171            return;
 9172        }
 9173
 9174        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9175            cx.propagate();
 9176            return;
 9177        }
 9178
 9179        let Some(row_count) = self.visible_row_count() else {
 9180            return;
 9181        };
 9182
 9183        let autoscroll = if action.center_cursor {
 9184            Autoscroll::center()
 9185        } else {
 9186            Autoscroll::fit()
 9187        };
 9188
 9189        let text_layout_details = &self.text_layout_details(window);
 9190        self.change_selections(Some(autoscroll), window, cx, |s| {
 9191            let line_mode = s.line_mode;
 9192            s.move_with(|map, selection| {
 9193                if !selection.is_empty() && !line_mode {
 9194                    selection.goal = SelectionGoal::None;
 9195                }
 9196                let (cursor, goal) = movement::down_by_rows(
 9197                    map,
 9198                    selection.end,
 9199                    row_count,
 9200                    selection.goal,
 9201                    false,
 9202                    text_layout_details,
 9203                );
 9204                selection.collapse_to(cursor, goal);
 9205            });
 9206        });
 9207    }
 9208
 9209    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
 9210        let text_layout_details = &self.text_layout_details(window);
 9211        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9212            s.move_heads_with(|map, head, goal| {
 9213                movement::down(map, head, goal, false, text_layout_details)
 9214            })
 9215        });
 9216    }
 9217
 9218    pub fn context_menu_first(
 9219        &mut self,
 9220        _: &ContextMenuFirst,
 9221        _window: &mut Window,
 9222        cx: &mut Context<Self>,
 9223    ) {
 9224        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
 9225            context_menu.select_first(self.completion_provider.as_deref(), cx);
 9226        }
 9227    }
 9228
 9229    pub fn context_menu_prev(
 9230        &mut self,
 9231        _: &ContextMenuPrev,
 9232        _window: &mut Window,
 9233        cx: &mut Context<Self>,
 9234    ) {
 9235        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
 9236            context_menu.select_prev(self.completion_provider.as_deref(), cx);
 9237        }
 9238    }
 9239
 9240    pub fn context_menu_next(
 9241        &mut self,
 9242        _: &ContextMenuNext,
 9243        _window: &mut Window,
 9244        cx: &mut Context<Self>,
 9245    ) {
 9246        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
 9247            context_menu.select_next(self.completion_provider.as_deref(), cx);
 9248        }
 9249    }
 9250
 9251    pub fn context_menu_last(
 9252        &mut self,
 9253        _: &ContextMenuLast,
 9254        _window: &mut Window,
 9255        cx: &mut Context<Self>,
 9256    ) {
 9257        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
 9258            context_menu.select_last(self.completion_provider.as_deref(), cx);
 9259        }
 9260    }
 9261
 9262    pub fn move_to_previous_word_start(
 9263        &mut self,
 9264        _: &MoveToPreviousWordStart,
 9265        window: &mut Window,
 9266        cx: &mut Context<Self>,
 9267    ) {
 9268        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9269            s.move_cursors_with(|map, head, _| {
 9270                (
 9271                    movement::previous_word_start(map, head),
 9272                    SelectionGoal::None,
 9273                )
 9274            });
 9275        })
 9276    }
 9277
 9278    pub fn move_to_previous_subword_start(
 9279        &mut self,
 9280        _: &MoveToPreviousSubwordStart,
 9281        window: &mut Window,
 9282        cx: &mut Context<Self>,
 9283    ) {
 9284        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9285            s.move_cursors_with(|map, head, _| {
 9286                (
 9287                    movement::previous_subword_start(map, head),
 9288                    SelectionGoal::None,
 9289                )
 9290            });
 9291        })
 9292    }
 9293
 9294    pub fn select_to_previous_word_start(
 9295        &mut self,
 9296        _: &SelectToPreviousWordStart,
 9297        window: &mut Window,
 9298        cx: &mut Context<Self>,
 9299    ) {
 9300        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9301            s.move_heads_with(|map, head, _| {
 9302                (
 9303                    movement::previous_word_start(map, head),
 9304                    SelectionGoal::None,
 9305                )
 9306            });
 9307        })
 9308    }
 9309
 9310    pub fn select_to_previous_subword_start(
 9311        &mut self,
 9312        _: &SelectToPreviousSubwordStart,
 9313        window: &mut Window,
 9314        cx: &mut Context<Self>,
 9315    ) {
 9316        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9317            s.move_heads_with(|map, head, _| {
 9318                (
 9319                    movement::previous_subword_start(map, head),
 9320                    SelectionGoal::None,
 9321                )
 9322            });
 9323        })
 9324    }
 9325
 9326    pub fn delete_to_previous_word_start(
 9327        &mut self,
 9328        action: &DeleteToPreviousWordStart,
 9329        window: &mut Window,
 9330        cx: &mut Context<Self>,
 9331    ) {
 9332        self.transact(window, cx, |this, window, cx| {
 9333            this.select_autoclose_pair(window, cx);
 9334            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9335                let line_mode = s.line_mode;
 9336                s.move_with(|map, selection| {
 9337                    if selection.is_empty() && !line_mode {
 9338                        let cursor = if action.ignore_newlines {
 9339                            movement::previous_word_start(map, selection.head())
 9340                        } else {
 9341                            movement::previous_word_start_or_newline(map, selection.head())
 9342                        };
 9343                        selection.set_head(cursor, SelectionGoal::None);
 9344                    }
 9345                });
 9346            });
 9347            this.insert("", window, cx);
 9348        });
 9349    }
 9350
 9351    pub fn delete_to_previous_subword_start(
 9352        &mut self,
 9353        _: &DeleteToPreviousSubwordStart,
 9354        window: &mut Window,
 9355        cx: &mut Context<Self>,
 9356    ) {
 9357        self.transact(window, cx, |this, window, cx| {
 9358            this.select_autoclose_pair(window, cx);
 9359            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9360                let line_mode = s.line_mode;
 9361                s.move_with(|map, selection| {
 9362                    if selection.is_empty() && !line_mode {
 9363                        let cursor = movement::previous_subword_start(map, selection.head());
 9364                        selection.set_head(cursor, SelectionGoal::None);
 9365                    }
 9366                });
 9367            });
 9368            this.insert("", window, cx);
 9369        });
 9370    }
 9371
 9372    pub fn move_to_next_word_end(
 9373        &mut self,
 9374        _: &MoveToNextWordEnd,
 9375        window: &mut Window,
 9376        cx: &mut Context<Self>,
 9377    ) {
 9378        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9379            s.move_cursors_with(|map, head, _| {
 9380                (movement::next_word_end(map, head), SelectionGoal::None)
 9381            });
 9382        })
 9383    }
 9384
 9385    pub fn move_to_next_subword_end(
 9386        &mut self,
 9387        _: &MoveToNextSubwordEnd,
 9388        window: &mut Window,
 9389        cx: &mut Context<Self>,
 9390    ) {
 9391        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9392            s.move_cursors_with(|map, head, _| {
 9393                (movement::next_subword_end(map, head), SelectionGoal::None)
 9394            });
 9395        })
 9396    }
 9397
 9398    pub fn select_to_next_word_end(
 9399        &mut self,
 9400        _: &SelectToNextWordEnd,
 9401        window: &mut Window,
 9402        cx: &mut Context<Self>,
 9403    ) {
 9404        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9405            s.move_heads_with(|map, head, _| {
 9406                (movement::next_word_end(map, head), SelectionGoal::None)
 9407            });
 9408        })
 9409    }
 9410
 9411    pub fn select_to_next_subword_end(
 9412        &mut self,
 9413        _: &SelectToNextSubwordEnd,
 9414        window: &mut Window,
 9415        cx: &mut Context<Self>,
 9416    ) {
 9417        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9418            s.move_heads_with(|map, head, _| {
 9419                (movement::next_subword_end(map, head), SelectionGoal::None)
 9420            });
 9421        })
 9422    }
 9423
 9424    pub fn delete_to_next_word_end(
 9425        &mut self,
 9426        action: &DeleteToNextWordEnd,
 9427        window: &mut Window,
 9428        cx: &mut Context<Self>,
 9429    ) {
 9430        self.transact(window, cx, |this, window, cx| {
 9431            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9432                let line_mode = s.line_mode;
 9433                s.move_with(|map, selection| {
 9434                    if selection.is_empty() && !line_mode {
 9435                        let cursor = if action.ignore_newlines {
 9436                            movement::next_word_end(map, selection.head())
 9437                        } else {
 9438                            movement::next_word_end_or_newline(map, selection.head())
 9439                        };
 9440                        selection.set_head(cursor, SelectionGoal::None);
 9441                    }
 9442                });
 9443            });
 9444            this.insert("", window, cx);
 9445        });
 9446    }
 9447
 9448    pub fn delete_to_next_subword_end(
 9449        &mut self,
 9450        _: &DeleteToNextSubwordEnd,
 9451        window: &mut Window,
 9452        cx: &mut Context<Self>,
 9453    ) {
 9454        self.transact(window, cx, |this, window, cx| {
 9455            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9456                s.move_with(|map, selection| {
 9457                    if selection.is_empty() {
 9458                        let cursor = movement::next_subword_end(map, selection.head());
 9459                        selection.set_head(cursor, SelectionGoal::None);
 9460                    }
 9461                });
 9462            });
 9463            this.insert("", window, cx);
 9464        });
 9465    }
 9466
 9467    pub fn move_to_beginning_of_line(
 9468        &mut self,
 9469        action: &MoveToBeginningOfLine,
 9470        window: &mut Window,
 9471        cx: &mut Context<Self>,
 9472    ) {
 9473        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9474            s.move_cursors_with(|map, head, _| {
 9475                (
 9476                    movement::indented_line_beginning(
 9477                        map,
 9478                        head,
 9479                        action.stop_at_soft_wraps,
 9480                        action.stop_at_indent,
 9481                    ),
 9482                    SelectionGoal::None,
 9483                )
 9484            });
 9485        })
 9486    }
 9487
 9488    pub fn select_to_beginning_of_line(
 9489        &mut self,
 9490        action: &SelectToBeginningOfLine,
 9491        window: &mut Window,
 9492        cx: &mut Context<Self>,
 9493    ) {
 9494        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9495            s.move_heads_with(|map, head, _| {
 9496                (
 9497                    movement::indented_line_beginning(
 9498                        map,
 9499                        head,
 9500                        action.stop_at_soft_wraps,
 9501                        action.stop_at_indent,
 9502                    ),
 9503                    SelectionGoal::None,
 9504                )
 9505            });
 9506        });
 9507    }
 9508
 9509    pub fn delete_to_beginning_of_line(
 9510        &mut self,
 9511        _: &DeleteToBeginningOfLine,
 9512        window: &mut Window,
 9513        cx: &mut Context<Self>,
 9514    ) {
 9515        self.transact(window, cx, |this, window, cx| {
 9516            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9517                s.move_with(|_, selection| {
 9518                    selection.reversed = true;
 9519                });
 9520            });
 9521
 9522            this.select_to_beginning_of_line(
 9523                &SelectToBeginningOfLine {
 9524                    stop_at_soft_wraps: false,
 9525                    stop_at_indent: false,
 9526                },
 9527                window,
 9528                cx,
 9529            );
 9530            this.backspace(&Backspace, window, cx);
 9531        });
 9532    }
 9533
 9534    pub fn move_to_end_of_line(
 9535        &mut self,
 9536        action: &MoveToEndOfLine,
 9537        window: &mut Window,
 9538        cx: &mut Context<Self>,
 9539    ) {
 9540        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9541            s.move_cursors_with(|map, head, _| {
 9542                (
 9543                    movement::line_end(map, head, action.stop_at_soft_wraps),
 9544                    SelectionGoal::None,
 9545                )
 9546            });
 9547        })
 9548    }
 9549
 9550    pub fn select_to_end_of_line(
 9551        &mut self,
 9552        action: &SelectToEndOfLine,
 9553        window: &mut Window,
 9554        cx: &mut Context<Self>,
 9555    ) {
 9556        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9557            s.move_heads_with(|map, head, _| {
 9558                (
 9559                    movement::line_end(map, head, action.stop_at_soft_wraps),
 9560                    SelectionGoal::None,
 9561                )
 9562            });
 9563        })
 9564    }
 9565
 9566    pub fn delete_to_end_of_line(
 9567        &mut self,
 9568        _: &DeleteToEndOfLine,
 9569        window: &mut Window,
 9570        cx: &mut Context<Self>,
 9571    ) {
 9572        self.transact(window, cx, |this, window, cx| {
 9573            this.select_to_end_of_line(
 9574                &SelectToEndOfLine {
 9575                    stop_at_soft_wraps: false,
 9576                },
 9577                window,
 9578                cx,
 9579            );
 9580            this.delete(&Delete, window, cx);
 9581        });
 9582    }
 9583
 9584    pub fn cut_to_end_of_line(
 9585        &mut self,
 9586        _: &CutToEndOfLine,
 9587        window: &mut Window,
 9588        cx: &mut Context<Self>,
 9589    ) {
 9590        self.transact(window, cx, |this, window, cx| {
 9591            this.select_to_end_of_line(
 9592                &SelectToEndOfLine {
 9593                    stop_at_soft_wraps: false,
 9594                },
 9595                window,
 9596                cx,
 9597            );
 9598            this.cut(&Cut, window, cx);
 9599        });
 9600    }
 9601
 9602    pub fn move_to_start_of_paragraph(
 9603        &mut self,
 9604        _: &MoveToStartOfParagraph,
 9605        window: &mut Window,
 9606        cx: &mut Context<Self>,
 9607    ) {
 9608        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9609            cx.propagate();
 9610            return;
 9611        }
 9612
 9613        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9614            s.move_with(|map, selection| {
 9615                selection.collapse_to(
 9616                    movement::start_of_paragraph(map, selection.head(), 1),
 9617                    SelectionGoal::None,
 9618                )
 9619            });
 9620        })
 9621    }
 9622
 9623    pub fn move_to_end_of_paragraph(
 9624        &mut self,
 9625        _: &MoveToEndOfParagraph,
 9626        window: &mut Window,
 9627        cx: &mut Context<Self>,
 9628    ) {
 9629        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9630            cx.propagate();
 9631            return;
 9632        }
 9633
 9634        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9635            s.move_with(|map, selection| {
 9636                selection.collapse_to(
 9637                    movement::end_of_paragraph(map, selection.head(), 1),
 9638                    SelectionGoal::None,
 9639                )
 9640            });
 9641        })
 9642    }
 9643
 9644    pub fn select_to_start_of_paragraph(
 9645        &mut self,
 9646        _: &SelectToStartOfParagraph,
 9647        window: &mut Window,
 9648        cx: &mut Context<Self>,
 9649    ) {
 9650        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9651            cx.propagate();
 9652            return;
 9653        }
 9654
 9655        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9656            s.move_heads_with(|map, head, _| {
 9657                (
 9658                    movement::start_of_paragraph(map, head, 1),
 9659                    SelectionGoal::None,
 9660                )
 9661            });
 9662        })
 9663    }
 9664
 9665    pub fn select_to_end_of_paragraph(
 9666        &mut self,
 9667        _: &SelectToEndOfParagraph,
 9668        window: &mut Window,
 9669        cx: &mut Context<Self>,
 9670    ) {
 9671        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9672            cx.propagate();
 9673            return;
 9674        }
 9675
 9676        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9677            s.move_heads_with(|map, head, _| {
 9678                (
 9679                    movement::end_of_paragraph(map, head, 1),
 9680                    SelectionGoal::None,
 9681                )
 9682            });
 9683        })
 9684    }
 9685
 9686    pub fn move_to_start_of_excerpt(
 9687        &mut self,
 9688        _: &MoveToStartOfExcerpt,
 9689        window: &mut Window,
 9690        cx: &mut Context<Self>,
 9691    ) {
 9692        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9693            cx.propagate();
 9694            return;
 9695        }
 9696
 9697        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9698            s.move_with(|map, selection| {
 9699                selection.collapse_to(
 9700                    movement::start_of_excerpt(
 9701                        map,
 9702                        selection.head(),
 9703                        workspace::searchable::Direction::Prev,
 9704                    ),
 9705                    SelectionGoal::None,
 9706                )
 9707            });
 9708        })
 9709    }
 9710
 9711    pub fn move_to_end_of_excerpt(
 9712        &mut self,
 9713        _: &MoveToEndOfExcerpt,
 9714        window: &mut Window,
 9715        cx: &mut Context<Self>,
 9716    ) {
 9717        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9718            cx.propagate();
 9719            return;
 9720        }
 9721
 9722        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9723            s.move_with(|map, selection| {
 9724                selection.collapse_to(
 9725                    movement::end_of_excerpt(
 9726                        map,
 9727                        selection.head(),
 9728                        workspace::searchable::Direction::Next,
 9729                    ),
 9730                    SelectionGoal::None,
 9731                )
 9732            });
 9733        })
 9734    }
 9735
 9736    pub fn select_to_start_of_excerpt(
 9737        &mut self,
 9738        _: &SelectToStartOfExcerpt,
 9739        window: &mut Window,
 9740        cx: &mut Context<Self>,
 9741    ) {
 9742        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9743            cx.propagate();
 9744            return;
 9745        }
 9746
 9747        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9748            s.move_heads_with(|map, head, _| {
 9749                (
 9750                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
 9751                    SelectionGoal::None,
 9752                )
 9753            });
 9754        })
 9755    }
 9756
 9757    pub fn select_to_end_of_excerpt(
 9758        &mut self,
 9759        _: &SelectToEndOfExcerpt,
 9760        window: &mut Window,
 9761        cx: &mut Context<Self>,
 9762    ) {
 9763        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9764            cx.propagate();
 9765            return;
 9766        }
 9767
 9768        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9769            s.move_heads_with(|map, head, _| {
 9770                (
 9771                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
 9772                    SelectionGoal::None,
 9773                )
 9774            });
 9775        })
 9776    }
 9777
 9778    pub fn move_to_beginning(
 9779        &mut self,
 9780        _: &MoveToBeginning,
 9781        window: &mut Window,
 9782        cx: &mut Context<Self>,
 9783    ) {
 9784        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9785            cx.propagate();
 9786            return;
 9787        }
 9788
 9789        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9790            s.select_ranges(vec![0..0]);
 9791        });
 9792    }
 9793
 9794    pub fn select_to_beginning(
 9795        &mut self,
 9796        _: &SelectToBeginning,
 9797        window: &mut Window,
 9798        cx: &mut Context<Self>,
 9799    ) {
 9800        let mut selection = self.selections.last::<Point>(cx);
 9801        selection.set_head(Point::zero(), SelectionGoal::None);
 9802
 9803        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9804            s.select(vec![selection]);
 9805        });
 9806    }
 9807
 9808    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
 9809        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 9810            cx.propagate();
 9811            return;
 9812        }
 9813
 9814        let cursor = self.buffer.read(cx).read(cx).len();
 9815        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9816            s.select_ranges(vec![cursor..cursor])
 9817        });
 9818    }
 9819
 9820    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
 9821        self.nav_history = nav_history;
 9822    }
 9823
 9824    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
 9825        self.nav_history.as_ref()
 9826    }
 9827
 9828    fn push_to_nav_history(
 9829        &mut self,
 9830        cursor_anchor: Anchor,
 9831        new_position: Option<Point>,
 9832        cx: &mut Context<Self>,
 9833    ) {
 9834        if let Some(nav_history) = self.nav_history.as_mut() {
 9835            let buffer = self.buffer.read(cx).read(cx);
 9836            let cursor_position = cursor_anchor.to_point(&buffer);
 9837            let scroll_state = self.scroll_manager.anchor();
 9838            let scroll_top_row = scroll_state.top_row(&buffer);
 9839            drop(buffer);
 9840
 9841            if let Some(new_position) = new_position {
 9842                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
 9843                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
 9844                    return;
 9845                }
 9846            }
 9847
 9848            nav_history.push(
 9849                Some(NavigationData {
 9850                    cursor_anchor,
 9851                    cursor_position,
 9852                    scroll_anchor: scroll_state,
 9853                    scroll_top_row,
 9854                }),
 9855                cx,
 9856            );
 9857        }
 9858    }
 9859
 9860    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
 9861        let buffer = self.buffer.read(cx).snapshot(cx);
 9862        let mut selection = self.selections.first::<usize>(cx);
 9863        selection.set_head(buffer.len(), SelectionGoal::None);
 9864        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9865            s.select(vec![selection]);
 9866        });
 9867    }
 9868
 9869    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
 9870        let end = self.buffer.read(cx).read(cx).len();
 9871        self.change_selections(None, window, cx, |s| {
 9872            s.select_ranges(vec![0..end]);
 9873        });
 9874    }
 9875
 9876    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
 9877        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9878        let mut selections = self.selections.all::<Point>(cx);
 9879        let max_point = display_map.buffer_snapshot.max_point();
 9880        for selection in &mut selections {
 9881            let rows = selection.spanned_rows(true, &display_map);
 9882            selection.start = Point::new(rows.start.0, 0);
 9883            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
 9884            selection.reversed = false;
 9885        }
 9886        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9887            s.select(selections);
 9888        });
 9889    }
 9890
 9891    pub fn split_selection_into_lines(
 9892        &mut self,
 9893        _: &SplitSelectionIntoLines,
 9894        window: &mut Window,
 9895        cx: &mut Context<Self>,
 9896    ) {
 9897        let selections = self
 9898            .selections
 9899            .all::<Point>(cx)
 9900            .into_iter()
 9901            .map(|selection| selection.start..selection.end)
 9902            .collect::<Vec<_>>();
 9903        self.unfold_ranges(&selections, true, true, cx);
 9904
 9905        let mut new_selection_ranges = Vec::new();
 9906        {
 9907            let buffer = self.buffer.read(cx).read(cx);
 9908            for selection in selections {
 9909                for row in selection.start.row..selection.end.row {
 9910                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
 9911                    new_selection_ranges.push(cursor..cursor);
 9912                }
 9913
 9914                let is_multiline_selection = selection.start.row != selection.end.row;
 9915                // Don't insert last one if it's a multi-line selection ending at the start of a line,
 9916                // so this action feels more ergonomic when paired with other selection operations
 9917                let should_skip_last = is_multiline_selection && selection.end.column == 0;
 9918                if !should_skip_last {
 9919                    new_selection_ranges.push(selection.end..selection.end);
 9920                }
 9921            }
 9922        }
 9923        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9924            s.select_ranges(new_selection_ranges);
 9925        });
 9926    }
 9927
 9928    pub fn add_selection_above(
 9929        &mut self,
 9930        _: &AddSelectionAbove,
 9931        window: &mut Window,
 9932        cx: &mut Context<Self>,
 9933    ) {
 9934        self.add_selection(true, window, cx);
 9935    }
 9936
 9937    pub fn add_selection_below(
 9938        &mut self,
 9939        _: &AddSelectionBelow,
 9940        window: &mut Window,
 9941        cx: &mut Context<Self>,
 9942    ) {
 9943        self.add_selection(false, window, cx);
 9944    }
 9945
 9946    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
 9947        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9948        let mut selections = self.selections.all::<Point>(cx);
 9949        let text_layout_details = self.text_layout_details(window);
 9950        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
 9951            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
 9952            let range = oldest_selection.display_range(&display_map).sorted();
 9953
 9954            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
 9955            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
 9956            let positions = start_x.min(end_x)..start_x.max(end_x);
 9957
 9958            selections.clear();
 9959            let mut stack = Vec::new();
 9960            for row in range.start.row().0..=range.end.row().0 {
 9961                if let Some(selection) = self.selections.build_columnar_selection(
 9962                    &display_map,
 9963                    DisplayRow(row),
 9964                    &positions,
 9965                    oldest_selection.reversed,
 9966                    &text_layout_details,
 9967                ) {
 9968                    stack.push(selection.id);
 9969                    selections.push(selection);
 9970                }
 9971            }
 9972
 9973            if above {
 9974                stack.reverse();
 9975            }
 9976
 9977            AddSelectionsState { above, stack }
 9978        });
 9979
 9980        let last_added_selection = *state.stack.last().unwrap();
 9981        let mut new_selections = Vec::new();
 9982        if above == state.above {
 9983            let end_row = if above {
 9984                DisplayRow(0)
 9985            } else {
 9986                display_map.max_point().row()
 9987            };
 9988
 9989            'outer: for selection in selections {
 9990                if selection.id == last_added_selection {
 9991                    let range = selection.display_range(&display_map).sorted();
 9992                    debug_assert_eq!(range.start.row(), range.end.row());
 9993                    let mut row = range.start.row();
 9994                    let positions =
 9995                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
 9996                            px(start)..px(end)
 9997                        } else {
 9998                            let start_x =
 9999                                display_map.x_for_display_point(range.start, &text_layout_details);
10000                            let end_x =
10001                                display_map.x_for_display_point(range.end, &text_layout_details);
10002                            start_x.min(end_x)..start_x.max(end_x)
10003                        };
10004
10005                    while row != end_row {
10006                        if above {
10007                            row.0 -= 1;
10008                        } else {
10009                            row.0 += 1;
10010                        }
10011
10012                        if let Some(new_selection) = self.selections.build_columnar_selection(
10013                            &display_map,
10014                            row,
10015                            &positions,
10016                            selection.reversed,
10017                            &text_layout_details,
10018                        ) {
10019                            state.stack.push(new_selection.id);
10020                            if above {
10021                                new_selections.push(new_selection);
10022                                new_selections.push(selection);
10023                            } else {
10024                                new_selections.push(selection);
10025                                new_selections.push(new_selection);
10026                            }
10027
10028                            continue 'outer;
10029                        }
10030                    }
10031                }
10032
10033                new_selections.push(selection);
10034            }
10035        } else {
10036            new_selections = selections;
10037            new_selections.retain(|s| s.id != last_added_selection);
10038            state.stack.pop();
10039        }
10040
10041        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10042            s.select(new_selections);
10043        });
10044        if state.stack.len() > 1 {
10045            self.add_selections_state = Some(state);
10046        }
10047    }
10048
10049    pub fn select_next_match_internal(
10050        &mut self,
10051        display_map: &DisplaySnapshot,
10052        replace_newest: bool,
10053        autoscroll: Option<Autoscroll>,
10054        window: &mut Window,
10055        cx: &mut Context<Self>,
10056    ) -> Result<()> {
10057        fn select_next_match_ranges(
10058            this: &mut Editor,
10059            range: Range<usize>,
10060            replace_newest: bool,
10061            auto_scroll: Option<Autoscroll>,
10062            window: &mut Window,
10063            cx: &mut Context<Editor>,
10064        ) {
10065            this.unfold_ranges(&[range.clone()], false, true, cx);
10066            this.change_selections(auto_scroll, window, cx, |s| {
10067                if replace_newest {
10068                    s.delete(s.newest_anchor().id);
10069                }
10070                s.insert_range(range.clone());
10071            });
10072        }
10073
10074        let buffer = &display_map.buffer_snapshot;
10075        let mut selections = self.selections.all::<usize>(cx);
10076        if let Some(mut select_next_state) = self.select_next_state.take() {
10077            let query = &select_next_state.query;
10078            if !select_next_state.done {
10079                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
10080                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
10081                let mut next_selected_range = None;
10082
10083                let bytes_after_last_selection =
10084                    buffer.bytes_in_range(last_selection.end..buffer.len());
10085                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
10086                let query_matches = query
10087                    .stream_find_iter(bytes_after_last_selection)
10088                    .map(|result| (last_selection.end, result))
10089                    .chain(
10090                        query
10091                            .stream_find_iter(bytes_before_first_selection)
10092                            .map(|result| (0, result)),
10093                    );
10094
10095                for (start_offset, query_match) in query_matches {
10096                    let query_match = query_match.unwrap(); // can only fail due to I/O
10097                    let offset_range =
10098                        start_offset + query_match.start()..start_offset + query_match.end();
10099                    let display_range = offset_range.start.to_display_point(display_map)
10100                        ..offset_range.end.to_display_point(display_map);
10101
10102                    if !select_next_state.wordwise
10103                        || (!movement::is_inside_word(display_map, display_range.start)
10104                            && !movement::is_inside_word(display_map, display_range.end))
10105                    {
10106                        // TODO: This is n^2, because we might check all the selections
10107                        if !selections
10108                            .iter()
10109                            .any(|selection| selection.range().overlaps(&offset_range))
10110                        {
10111                            next_selected_range = Some(offset_range);
10112                            break;
10113                        }
10114                    }
10115                }
10116
10117                if let Some(next_selected_range) = next_selected_range {
10118                    select_next_match_ranges(
10119                        self,
10120                        next_selected_range,
10121                        replace_newest,
10122                        autoscroll,
10123                        window,
10124                        cx,
10125                    );
10126                } else {
10127                    select_next_state.done = true;
10128                }
10129            }
10130
10131            self.select_next_state = Some(select_next_state);
10132        } else {
10133            let mut only_carets = true;
10134            let mut same_text_selected = true;
10135            let mut selected_text = None;
10136
10137            let mut selections_iter = selections.iter().peekable();
10138            while let Some(selection) = selections_iter.next() {
10139                if selection.start != selection.end {
10140                    only_carets = false;
10141                }
10142
10143                if same_text_selected {
10144                    if selected_text.is_none() {
10145                        selected_text =
10146                            Some(buffer.text_for_range(selection.range()).collect::<String>());
10147                    }
10148
10149                    if let Some(next_selection) = selections_iter.peek() {
10150                        if next_selection.range().len() == selection.range().len() {
10151                            let next_selected_text = buffer
10152                                .text_for_range(next_selection.range())
10153                                .collect::<String>();
10154                            if Some(next_selected_text) != selected_text {
10155                                same_text_selected = false;
10156                                selected_text = None;
10157                            }
10158                        } else {
10159                            same_text_selected = false;
10160                            selected_text = None;
10161                        }
10162                    }
10163                }
10164            }
10165
10166            if only_carets {
10167                for selection in &mut selections {
10168                    let word_range = movement::surrounding_word(
10169                        display_map,
10170                        selection.start.to_display_point(display_map),
10171                    );
10172                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
10173                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
10174                    selection.goal = SelectionGoal::None;
10175                    selection.reversed = false;
10176                    select_next_match_ranges(
10177                        self,
10178                        selection.start..selection.end,
10179                        replace_newest,
10180                        autoscroll,
10181                        window,
10182                        cx,
10183                    );
10184                }
10185
10186                if selections.len() == 1 {
10187                    let selection = selections
10188                        .last()
10189                        .expect("ensured that there's only one selection");
10190                    let query = buffer
10191                        .text_for_range(selection.start..selection.end)
10192                        .collect::<String>();
10193                    let is_empty = query.is_empty();
10194                    let select_state = SelectNextState {
10195                        query: AhoCorasick::new(&[query])?,
10196                        wordwise: true,
10197                        done: is_empty,
10198                    };
10199                    self.select_next_state = Some(select_state);
10200                } else {
10201                    self.select_next_state = None;
10202                }
10203            } else if let Some(selected_text) = selected_text {
10204                self.select_next_state = Some(SelectNextState {
10205                    query: AhoCorasick::new(&[selected_text])?,
10206                    wordwise: false,
10207                    done: false,
10208                });
10209                self.select_next_match_internal(
10210                    display_map,
10211                    replace_newest,
10212                    autoscroll,
10213                    window,
10214                    cx,
10215                )?;
10216            }
10217        }
10218        Ok(())
10219    }
10220
10221    pub fn select_all_matches(
10222        &mut self,
10223        _action: &SelectAllMatches,
10224        window: &mut Window,
10225        cx: &mut Context<Self>,
10226    ) -> Result<()> {
10227        self.push_to_selection_history();
10228        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10229
10230        self.select_next_match_internal(&display_map, false, None, window, cx)?;
10231        let Some(select_next_state) = self.select_next_state.as_mut() else {
10232            return Ok(());
10233        };
10234        if select_next_state.done {
10235            return Ok(());
10236        }
10237
10238        let mut new_selections = self.selections.all::<usize>(cx);
10239
10240        let buffer = &display_map.buffer_snapshot;
10241        let query_matches = select_next_state
10242            .query
10243            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
10244
10245        for query_match in query_matches {
10246            let query_match = query_match.unwrap(); // can only fail due to I/O
10247            let offset_range = query_match.start()..query_match.end();
10248            let display_range = offset_range.start.to_display_point(&display_map)
10249                ..offset_range.end.to_display_point(&display_map);
10250
10251            if !select_next_state.wordwise
10252                || (!movement::is_inside_word(&display_map, display_range.start)
10253                    && !movement::is_inside_word(&display_map, display_range.end))
10254            {
10255                self.selections.change_with(cx, |selections| {
10256                    new_selections.push(Selection {
10257                        id: selections.new_selection_id(),
10258                        start: offset_range.start,
10259                        end: offset_range.end,
10260                        reversed: false,
10261                        goal: SelectionGoal::None,
10262                    });
10263                });
10264            }
10265        }
10266
10267        new_selections.sort_by_key(|selection| selection.start);
10268        let mut ix = 0;
10269        while ix + 1 < new_selections.len() {
10270            let current_selection = &new_selections[ix];
10271            let next_selection = &new_selections[ix + 1];
10272            if current_selection.range().overlaps(&next_selection.range()) {
10273                if current_selection.id < next_selection.id {
10274                    new_selections.remove(ix + 1);
10275                } else {
10276                    new_selections.remove(ix);
10277                }
10278            } else {
10279                ix += 1;
10280            }
10281        }
10282
10283        let reversed = self.selections.oldest::<usize>(cx).reversed;
10284
10285        for selection in new_selections.iter_mut() {
10286            selection.reversed = reversed;
10287        }
10288
10289        select_next_state.done = true;
10290        self.unfold_ranges(
10291            &new_selections
10292                .iter()
10293                .map(|selection| selection.range())
10294                .collect::<Vec<_>>(),
10295            false,
10296            false,
10297            cx,
10298        );
10299        self.change_selections(Some(Autoscroll::fit()), window, cx, |selections| {
10300            selections.select(new_selections)
10301        });
10302
10303        Ok(())
10304    }
10305
10306    pub fn select_next(
10307        &mut self,
10308        action: &SelectNext,
10309        window: &mut Window,
10310        cx: &mut Context<Self>,
10311    ) -> Result<()> {
10312        self.push_to_selection_history();
10313        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10314        self.select_next_match_internal(
10315            &display_map,
10316            action.replace_newest,
10317            Some(Autoscroll::newest()),
10318            window,
10319            cx,
10320        )?;
10321        Ok(())
10322    }
10323
10324    pub fn select_previous(
10325        &mut self,
10326        action: &SelectPrevious,
10327        window: &mut Window,
10328        cx: &mut Context<Self>,
10329    ) -> Result<()> {
10330        self.push_to_selection_history();
10331        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10332        let buffer = &display_map.buffer_snapshot;
10333        let mut selections = self.selections.all::<usize>(cx);
10334        if let Some(mut select_prev_state) = self.select_prev_state.take() {
10335            let query = &select_prev_state.query;
10336            if !select_prev_state.done {
10337                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
10338                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
10339                let mut next_selected_range = None;
10340                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
10341                let bytes_before_last_selection =
10342                    buffer.reversed_bytes_in_range(0..last_selection.start);
10343                let bytes_after_first_selection =
10344                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
10345                let query_matches = query
10346                    .stream_find_iter(bytes_before_last_selection)
10347                    .map(|result| (last_selection.start, result))
10348                    .chain(
10349                        query
10350                            .stream_find_iter(bytes_after_first_selection)
10351                            .map(|result| (buffer.len(), result)),
10352                    );
10353                for (end_offset, query_match) in query_matches {
10354                    let query_match = query_match.unwrap(); // can only fail due to I/O
10355                    let offset_range =
10356                        end_offset - query_match.end()..end_offset - query_match.start();
10357                    let display_range = offset_range.start.to_display_point(&display_map)
10358                        ..offset_range.end.to_display_point(&display_map);
10359
10360                    if !select_prev_state.wordwise
10361                        || (!movement::is_inside_word(&display_map, display_range.start)
10362                            && !movement::is_inside_word(&display_map, display_range.end))
10363                    {
10364                        next_selected_range = Some(offset_range);
10365                        break;
10366                    }
10367                }
10368
10369                if let Some(next_selected_range) = next_selected_range {
10370                    self.unfold_ranges(&[next_selected_range.clone()], false, true, cx);
10371                    self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
10372                        if action.replace_newest {
10373                            s.delete(s.newest_anchor().id);
10374                        }
10375                        s.insert_range(next_selected_range);
10376                    });
10377                } else {
10378                    select_prev_state.done = true;
10379                }
10380            }
10381
10382            self.select_prev_state = Some(select_prev_state);
10383        } else {
10384            let mut only_carets = true;
10385            let mut same_text_selected = true;
10386            let mut selected_text = None;
10387
10388            let mut selections_iter = selections.iter().peekable();
10389            while let Some(selection) = selections_iter.next() {
10390                if selection.start != selection.end {
10391                    only_carets = false;
10392                }
10393
10394                if same_text_selected {
10395                    if selected_text.is_none() {
10396                        selected_text =
10397                            Some(buffer.text_for_range(selection.range()).collect::<String>());
10398                    }
10399
10400                    if let Some(next_selection) = selections_iter.peek() {
10401                        if next_selection.range().len() == selection.range().len() {
10402                            let next_selected_text = buffer
10403                                .text_for_range(next_selection.range())
10404                                .collect::<String>();
10405                            if Some(next_selected_text) != selected_text {
10406                                same_text_selected = false;
10407                                selected_text = None;
10408                            }
10409                        } else {
10410                            same_text_selected = false;
10411                            selected_text = None;
10412                        }
10413                    }
10414                }
10415            }
10416
10417            if only_carets {
10418                for selection in &mut selections {
10419                    let word_range = movement::surrounding_word(
10420                        &display_map,
10421                        selection.start.to_display_point(&display_map),
10422                    );
10423                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
10424                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
10425                    selection.goal = SelectionGoal::None;
10426                    selection.reversed = false;
10427                }
10428                if selections.len() == 1 {
10429                    let selection = selections
10430                        .last()
10431                        .expect("ensured that there's only one selection");
10432                    let query = buffer
10433                        .text_for_range(selection.start..selection.end)
10434                        .collect::<String>();
10435                    let is_empty = query.is_empty();
10436                    let select_state = SelectNextState {
10437                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
10438                        wordwise: true,
10439                        done: is_empty,
10440                    };
10441                    self.select_prev_state = Some(select_state);
10442                } else {
10443                    self.select_prev_state = None;
10444                }
10445
10446                self.unfold_ranges(
10447                    &selections.iter().map(|s| s.range()).collect::<Vec<_>>(),
10448                    false,
10449                    true,
10450                    cx,
10451                );
10452                self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
10453                    s.select(selections);
10454                });
10455            } else if let Some(selected_text) = selected_text {
10456                self.select_prev_state = Some(SelectNextState {
10457                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
10458                    wordwise: false,
10459                    done: false,
10460                });
10461                self.select_previous(action, window, cx)?;
10462            }
10463        }
10464        Ok(())
10465    }
10466
10467    pub fn toggle_comments(
10468        &mut self,
10469        action: &ToggleComments,
10470        window: &mut Window,
10471        cx: &mut Context<Self>,
10472    ) {
10473        if self.read_only(cx) {
10474            return;
10475        }
10476        let text_layout_details = &self.text_layout_details(window);
10477        self.transact(window, cx, |this, window, cx| {
10478            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
10479            let mut edits = Vec::new();
10480            let mut selection_edit_ranges = Vec::new();
10481            let mut last_toggled_row = None;
10482            let snapshot = this.buffer.read(cx).read(cx);
10483            let empty_str: Arc<str> = Arc::default();
10484            let mut suffixes_inserted = Vec::new();
10485            let ignore_indent = action.ignore_indent;
10486
10487            fn comment_prefix_range(
10488                snapshot: &MultiBufferSnapshot,
10489                row: MultiBufferRow,
10490                comment_prefix: &str,
10491                comment_prefix_whitespace: &str,
10492                ignore_indent: bool,
10493            ) -> Range<Point> {
10494                let indent_size = if ignore_indent {
10495                    0
10496                } else {
10497                    snapshot.indent_size_for_line(row).len
10498                };
10499
10500                let start = Point::new(row.0, indent_size);
10501
10502                let mut line_bytes = snapshot
10503                    .bytes_in_range(start..snapshot.max_point())
10504                    .flatten()
10505                    .copied();
10506
10507                // If this line currently begins with the line comment prefix, then record
10508                // the range containing the prefix.
10509                if line_bytes
10510                    .by_ref()
10511                    .take(comment_prefix.len())
10512                    .eq(comment_prefix.bytes())
10513                {
10514                    // Include any whitespace that matches the comment prefix.
10515                    let matching_whitespace_len = line_bytes
10516                        .zip(comment_prefix_whitespace.bytes())
10517                        .take_while(|(a, b)| a == b)
10518                        .count() as u32;
10519                    let end = Point::new(
10520                        start.row,
10521                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
10522                    );
10523                    start..end
10524                } else {
10525                    start..start
10526                }
10527            }
10528
10529            fn comment_suffix_range(
10530                snapshot: &MultiBufferSnapshot,
10531                row: MultiBufferRow,
10532                comment_suffix: &str,
10533                comment_suffix_has_leading_space: bool,
10534            ) -> Range<Point> {
10535                let end = Point::new(row.0, snapshot.line_len(row));
10536                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
10537
10538                let mut line_end_bytes = snapshot
10539                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
10540                    .flatten()
10541                    .copied();
10542
10543                let leading_space_len = if suffix_start_column > 0
10544                    && line_end_bytes.next() == Some(b' ')
10545                    && comment_suffix_has_leading_space
10546                {
10547                    1
10548                } else {
10549                    0
10550                };
10551
10552                // If this line currently begins with the line comment prefix, then record
10553                // the range containing the prefix.
10554                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
10555                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
10556                    start..end
10557                } else {
10558                    end..end
10559                }
10560            }
10561
10562            // TODO: Handle selections that cross excerpts
10563            for selection in &mut selections {
10564                let start_column = snapshot
10565                    .indent_size_for_line(MultiBufferRow(selection.start.row))
10566                    .len;
10567                let language = if let Some(language) =
10568                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
10569                {
10570                    language
10571                } else {
10572                    continue;
10573                };
10574
10575                selection_edit_ranges.clear();
10576
10577                // If multiple selections contain a given row, avoid processing that
10578                // row more than once.
10579                let mut start_row = MultiBufferRow(selection.start.row);
10580                if last_toggled_row == Some(start_row) {
10581                    start_row = start_row.next_row();
10582                }
10583                let end_row =
10584                    if selection.end.row > selection.start.row && selection.end.column == 0 {
10585                        MultiBufferRow(selection.end.row - 1)
10586                    } else {
10587                        MultiBufferRow(selection.end.row)
10588                    };
10589                last_toggled_row = Some(end_row);
10590
10591                if start_row > end_row {
10592                    continue;
10593                }
10594
10595                // If the language has line comments, toggle those.
10596                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
10597
10598                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
10599                if ignore_indent {
10600                    full_comment_prefixes = full_comment_prefixes
10601                        .into_iter()
10602                        .map(|s| Arc::from(s.trim_end()))
10603                        .collect();
10604                }
10605
10606                if !full_comment_prefixes.is_empty() {
10607                    let first_prefix = full_comment_prefixes
10608                        .first()
10609                        .expect("prefixes is non-empty");
10610                    let prefix_trimmed_lengths = full_comment_prefixes
10611                        .iter()
10612                        .map(|p| p.trim_end_matches(' ').len())
10613                        .collect::<SmallVec<[usize; 4]>>();
10614
10615                    let mut all_selection_lines_are_comments = true;
10616
10617                    for row in start_row.0..=end_row.0 {
10618                        let row = MultiBufferRow(row);
10619                        if start_row < end_row && snapshot.is_line_blank(row) {
10620                            continue;
10621                        }
10622
10623                        let prefix_range = full_comment_prefixes
10624                            .iter()
10625                            .zip(prefix_trimmed_lengths.iter().copied())
10626                            .map(|(prefix, trimmed_prefix_len)| {
10627                                comment_prefix_range(
10628                                    snapshot.deref(),
10629                                    row,
10630                                    &prefix[..trimmed_prefix_len],
10631                                    &prefix[trimmed_prefix_len..],
10632                                    ignore_indent,
10633                                )
10634                            })
10635                            .max_by_key(|range| range.end.column - range.start.column)
10636                            .expect("prefixes is non-empty");
10637
10638                        if prefix_range.is_empty() {
10639                            all_selection_lines_are_comments = false;
10640                        }
10641
10642                        selection_edit_ranges.push(prefix_range);
10643                    }
10644
10645                    if all_selection_lines_are_comments {
10646                        edits.extend(
10647                            selection_edit_ranges
10648                                .iter()
10649                                .cloned()
10650                                .map(|range| (range, empty_str.clone())),
10651                        );
10652                    } else {
10653                        let min_column = selection_edit_ranges
10654                            .iter()
10655                            .map(|range| range.start.column)
10656                            .min()
10657                            .unwrap_or(0);
10658                        edits.extend(selection_edit_ranges.iter().map(|range| {
10659                            let position = Point::new(range.start.row, min_column);
10660                            (position..position, first_prefix.clone())
10661                        }));
10662                    }
10663                } else if let Some((full_comment_prefix, comment_suffix)) =
10664                    language.block_comment_delimiters()
10665                {
10666                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
10667                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
10668                    let prefix_range = comment_prefix_range(
10669                        snapshot.deref(),
10670                        start_row,
10671                        comment_prefix,
10672                        comment_prefix_whitespace,
10673                        ignore_indent,
10674                    );
10675                    let suffix_range = comment_suffix_range(
10676                        snapshot.deref(),
10677                        end_row,
10678                        comment_suffix.trim_start_matches(' '),
10679                        comment_suffix.starts_with(' '),
10680                    );
10681
10682                    if prefix_range.is_empty() || suffix_range.is_empty() {
10683                        edits.push((
10684                            prefix_range.start..prefix_range.start,
10685                            full_comment_prefix.clone(),
10686                        ));
10687                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
10688                        suffixes_inserted.push((end_row, comment_suffix.len()));
10689                    } else {
10690                        edits.push((prefix_range, empty_str.clone()));
10691                        edits.push((suffix_range, empty_str.clone()));
10692                    }
10693                } else {
10694                    continue;
10695                }
10696            }
10697
10698            drop(snapshot);
10699            this.buffer.update(cx, |buffer, cx| {
10700                buffer.edit(edits, None, cx);
10701            });
10702
10703            // Adjust selections so that they end before any comment suffixes that
10704            // were inserted.
10705            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
10706            let mut selections = this.selections.all::<Point>(cx);
10707            let snapshot = this.buffer.read(cx).read(cx);
10708            for selection in &mut selections {
10709                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
10710                    match row.cmp(&MultiBufferRow(selection.end.row)) {
10711                        Ordering::Less => {
10712                            suffixes_inserted.next();
10713                            continue;
10714                        }
10715                        Ordering::Greater => break,
10716                        Ordering::Equal => {
10717                            if selection.end.column == snapshot.line_len(row) {
10718                                if selection.is_empty() {
10719                                    selection.start.column -= suffix_len as u32;
10720                                }
10721                                selection.end.column -= suffix_len as u32;
10722                            }
10723                            break;
10724                        }
10725                    }
10726                }
10727            }
10728
10729            drop(snapshot);
10730            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10731                s.select(selections)
10732            });
10733
10734            let selections = this.selections.all::<Point>(cx);
10735            let selections_on_single_row = selections.windows(2).all(|selections| {
10736                selections[0].start.row == selections[1].start.row
10737                    && selections[0].end.row == selections[1].end.row
10738                    && selections[0].start.row == selections[0].end.row
10739            });
10740            let selections_selecting = selections
10741                .iter()
10742                .any(|selection| selection.start != selection.end);
10743            let advance_downwards = action.advance_downwards
10744                && selections_on_single_row
10745                && !selections_selecting
10746                && !matches!(this.mode, EditorMode::SingleLine { .. });
10747
10748            if advance_downwards {
10749                let snapshot = this.buffer.read(cx).snapshot(cx);
10750
10751                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10752                    s.move_cursors_with(|display_snapshot, display_point, _| {
10753                        let mut point = display_point.to_point(display_snapshot);
10754                        point.row += 1;
10755                        point = snapshot.clip_point(point, Bias::Left);
10756                        let display_point = point.to_display_point(display_snapshot);
10757                        let goal = SelectionGoal::HorizontalPosition(
10758                            display_snapshot
10759                                .x_for_display_point(display_point, text_layout_details)
10760                                .into(),
10761                        );
10762                        (display_point, goal)
10763                    })
10764                });
10765            }
10766        });
10767    }
10768
10769    pub fn select_enclosing_symbol(
10770        &mut self,
10771        _: &SelectEnclosingSymbol,
10772        window: &mut Window,
10773        cx: &mut Context<Self>,
10774    ) {
10775        let buffer = self.buffer.read(cx).snapshot(cx);
10776        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
10777
10778        fn update_selection(
10779            selection: &Selection<usize>,
10780            buffer_snap: &MultiBufferSnapshot,
10781        ) -> Option<Selection<usize>> {
10782            let cursor = selection.head();
10783            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
10784            for symbol in symbols.iter().rev() {
10785                let start = symbol.range.start.to_offset(buffer_snap);
10786                let end = symbol.range.end.to_offset(buffer_snap);
10787                let new_range = start..end;
10788                if start < selection.start || end > selection.end {
10789                    return Some(Selection {
10790                        id: selection.id,
10791                        start: new_range.start,
10792                        end: new_range.end,
10793                        goal: SelectionGoal::None,
10794                        reversed: selection.reversed,
10795                    });
10796                }
10797            }
10798            None
10799        }
10800
10801        let mut selected_larger_symbol = false;
10802        let new_selections = old_selections
10803            .iter()
10804            .map(|selection| match update_selection(selection, &buffer) {
10805                Some(new_selection) => {
10806                    if new_selection.range() != selection.range() {
10807                        selected_larger_symbol = true;
10808                    }
10809                    new_selection
10810                }
10811                None => selection.clone(),
10812            })
10813            .collect::<Vec<_>>();
10814
10815        if selected_larger_symbol {
10816            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10817                s.select(new_selections);
10818            });
10819        }
10820    }
10821
10822    pub fn select_larger_syntax_node(
10823        &mut self,
10824        _: &SelectLargerSyntaxNode,
10825        window: &mut Window,
10826        cx: &mut Context<Self>,
10827    ) {
10828        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10829        let buffer = self.buffer.read(cx).snapshot(cx);
10830        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
10831
10832        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
10833        let mut selected_larger_node = false;
10834        let new_selections = old_selections
10835            .iter()
10836            .map(|selection| {
10837                let old_range = selection.start..selection.end;
10838                let mut new_range = old_range.clone();
10839                let mut new_node = None;
10840                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
10841                {
10842                    new_node = Some(node);
10843                    new_range = match containing_range {
10844                        MultiOrSingleBufferOffsetRange::Single(_) => break,
10845                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
10846                    };
10847                    if !display_map.intersects_fold(new_range.start)
10848                        && !display_map.intersects_fold(new_range.end)
10849                    {
10850                        break;
10851                    }
10852                }
10853
10854                if let Some(node) = new_node {
10855                    // Log the ancestor, to support using this action as a way to explore TreeSitter
10856                    // nodes. Parent and grandparent are also logged because this operation will not
10857                    // visit nodes that have the same range as their parent.
10858                    log::info!("Node: {node:?}");
10859                    let parent = node.parent();
10860                    log::info!("Parent: {parent:?}");
10861                    let grandparent = parent.and_then(|x| x.parent());
10862                    log::info!("Grandparent: {grandparent:?}");
10863                }
10864
10865                selected_larger_node |= new_range != old_range;
10866                Selection {
10867                    id: selection.id,
10868                    start: new_range.start,
10869                    end: new_range.end,
10870                    goal: SelectionGoal::None,
10871                    reversed: selection.reversed,
10872                }
10873            })
10874            .collect::<Vec<_>>();
10875
10876        if selected_larger_node {
10877            stack.push(old_selections);
10878            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10879                s.select(new_selections);
10880            });
10881        }
10882        self.select_larger_syntax_node_stack = stack;
10883    }
10884
10885    pub fn select_smaller_syntax_node(
10886        &mut self,
10887        _: &SelectSmallerSyntaxNode,
10888        window: &mut Window,
10889        cx: &mut Context<Self>,
10890    ) {
10891        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
10892        if let Some(selections) = stack.pop() {
10893            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10894                s.select(selections.to_vec());
10895            });
10896        }
10897        self.select_larger_syntax_node_stack = stack;
10898    }
10899
10900    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
10901        if !EditorSettings::get_global(cx).gutter.runnables {
10902            self.clear_tasks();
10903            return Task::ready(());
10904        }
10905        let project = self.project.as_ref().map(Entity::downgrade);
10906        cx.spawn_in(window, |this, mut cx| async move {
10907            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
10908            let Some(project) = project.and_then(|p| p.upgrade()) else {
10909                return;
10910            };
10911            let Ok(display_snapshot) = this.update(&mut cx, |this, cx| {
10912                this.display_map.update(cx, |map, cx| map.snapshot(cx))
10913            }) else {
10914                return;
10915            };
10916
10917            let hide_runnables = project
10918                .update(&mut cx, |project, cx| {
10919                    // Do not display any test indicators in non-dev server remote projects.
10920                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
10921                })
10922                .unwrap_or(true);
10923            if hide_runnables {
10924                return;
10925            }
10926            let new_rows =
10927                cx.background_spawn({
10928                    let snapshot = display_snapshot.clone();
10929                    async move {
10930                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
10931                    }
10932                })
10933                    .await;
10934
10935            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
10936            this.update(&mut cx, |this, _| {
10937                this.clear_tasks();
10938                for (key, value) in rows {
10939                    this.insert_tasks(key, value);
10940                }
10941            })
10942            .ok();
10943        })
10944    }
10945    fn fetch_runnable_ranges(
10946        snapshot: &DisplaySnapshot,
10947        range: Range<Anchor>,
10948    ) -> Vec<language::RunnableRange> {
10949        snapshot.buffer_snapshot.runnable_ranges(range).collect()
10950    }
10951
10952    fn runnable_rows(
10953        project: Entity<Project>,
10954        snapshot: DisplaySnapshot,
10955        runnable_ranges: Vec<RunnableRange>,
10956        mut cx: AsyncWindowContext,
10957    ) -> Vec<((BufferId, u32), RunnableTasks)> {
10958        runnable_ranges
10959            .into_iter()
10960            .filter_map(|mut runnable| {
10961                let tasks = cx
10962                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
10963                    .ok()?;
10964                if tasks.is_empty() {
10965                    return None;
10966                }
10967
10968                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
10969
10970                let row = snapshot
10971                    .buffer_snapshot
10972                    .buffer_line_for_row(MultiBufferRow(point.row))?
10973                    .1
10974                    .start
10975                    .row;
10976
10977                let context_range =
10978                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
10979                Some((
10980                    (runnable.buffer_id, row),
10981                    RunnableTasks {
10982                        templates: tasks,
10983                        offset: snapshot
10984                            .buffer_snapshot
10985                            .anchor_before(runnable.run_range.start),
10986                        context_range,
10987                        column: point.column,
10988                        extra_variables: runnable.extra_captures,
10989                    },
10990                ))
10991            })
10992            .collect()
10993    }
10994
10995    fn templates_with_tags(
10996        project: &Entity<Project>,
10997        runnable: &mut Runnable,
10998        cx: &mut App,
10999    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
11000        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
11001            let (worktree_id, file) = project
11002                .buffer_for_id(runnable.buffer, cx)
11003                .and_then(|buffer| buffer.read(cx).file())
11004                .map(|file| (file.worktree_id(cx), file.clone()))
11005                .unzip();
11006
11007            (
11008                project.task_store().read(cx).task_inventory().cloned(),
11009                worktree_id,
11010                file,
11011            )
11012        });
11013
11014        let tags = mem::take(&mut runnable.tags);
11015        let mut tags: Vec<_> = tags
11016            .into_iter()
11017            .flat_map(|tag| {
11018                let tag = tag.0.clone();
11019                inventory
11020                    .as_ref()
11021                    .into_iter()
11022                    .flat_map(|inventory| {
11023                        inventory.read(cx).list_tasks(
11024                            file.clone(),
11025                            Some(runnable.language.clone()),
11026                            worktree_id,
11027                            cx,
11028                        )
11029                    })
11030                    .filter(move |(_, template)| {
11031                        template.tags.iter().any(|source_tag| source_tag == &tag)
11032                    })
11033            })
11034            .sorted_by_key(|(kind, _)| kind.to_owned())
11035            .collect();
11036        if let Some((leading_tag_source, _)) = tags.first() {
11037            // Strongest source wins; if we have worktree tag binding, prefer that to
11038            // global and language bindings;
11039            // if we have a global binding, prefer that to language binding.
11040            let first_mismatch = tags
11041                .iter()
11042                .position(|(tag_source, _)| tag_source != leading_tag_source);
11043            if let Some(index) = first_mismatch {
11044                tags.truncate(index);
11045            }
11046        }
11047
11048        tags
11049    }
11050
11051    pub fn move_to_enclosing_bracket(
11052        &mut self,
11053        _: &MoveToEnclosingBracket,
11054        window: &mut Window,
11055        cx: &mut Context<Self>,
11056    ) {
11057        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11058            s.move_offsets_with(|snapshot, selection| {
11059                let Some(enclosing_bracket_ranges) =
11060                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
11061                else {
11062                    return;
11063                };
11064
11065                let mut best_length = usize::MAX;
11066                let mut best_inside = false;
11067                let mut best_in_bracket_range = false;
11068                let mut best_destination = None;
11069                for (open, close) in enclosing_bracket_ranges {
11070                    let close = close.to_inclusive();
11071                    let length = close.end() - open.start;
11072                    let inside = selection.start >= open.end && selection.end <= *close.start();
11073                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
11074                        || close.contains(&selection.head());
11075
11076                    // If best is next to a bracket and current isn't, skip
11077                    if !in_bracket_range && best_in_bracket_range {
11078                        continue;
11079                    }
11080
11081                    // Prefer smaller lengths unless best is inside and current isn't
11082                    if length > best_length && (best_inside || !inside) {
11083                        continue;
11084                    }
11085
11086                    best_length = length;
11087                    best_inside = inside;
11088                    best_in_bracket_range = in_bracket_range;
11089                    best_destination = Some(
11090                        if close.contains(&selection.start) && close.contains(&selection.end) {
11091                            if inside {
11092                                open.end
11093                            } else {
11094                                open.start
11095                            }
11096                        } else if inside {
11097                            *close.start()
11098                        } else {
11099                            *close.end()
11100                        },
11101                    );
11102                }
11103
11104                if let Some(destination) = best_destination {
11105                    selection.collapse_to(destination, SelectionGoal::None);
11106                }
11107            })
11108        });
11109    }
11110
11111    pub fn undo_selection(
11112        &mut self,
11113        _: &UndoSelection,
11114        window: &mut Window,
11115        cx: &mut Context<Self>,
11116    ) {
11117        self.end_selection(window, cx);
11118        self.selection_history.mode = SelectionHistoryMode::Undoing;
11119        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
11120            self.change_selections(None, window, cx, |s| {
11121                s.select_anchors(entry.selections.to_vec())
11122            });
11123            self.select_next_state = entry.select_next_state;
11124            self.select_prev_state = entry.select_prev_state;
11125            self.add_selections_state = entry.add_selections_state;
11126            self.request_autoscroll(Autoscroll::newest(), cx);
11127        }
11128        self.selection_history.mode = SelectionHistoryMode::Normal;
11129    }
11130
11131    pub fn redo_selection(
11132        &mut self,
11133        _: &RedoSelection,
11134        window: &mut Window,
11135        cx: &mut Context<Self>,
11136    ) {
11137        self.end_selection(window, cx);
11138        self.selection_history.mode = SelectionHistoryMode::Redoing;
11139        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
11140            self.change_selections(None, window, cx, |s| {
11141                s.select_anchors(entry.selections.to_vec())
11142            });
11143            self.select_next_state = entry.select_next_state;
11144            self.select_prev_state = entry.select_prev_state;
11145            self.add_selections_state = entry.add_selections_state;
11146            self.request_autoscroll(Autoscroll::newest(), cx);
11147        }
11148        self.selection_history.mode = SelectionHistoryMode::Normal;
11149    }
11150
11151    pub fn expand_excerpts(
11152        &mut self,
11153        action: &ExpandExcerpts,
11154        _: &mut Window,
11155        cx: &mut Context<Self>,
11156    ) {
11157        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
11158    }
11159
11160    pub fn expand_excerpts_down(
11161        &mut self,
11162        action: &ExpandExcerptsDown,
11163        _: &mut Window,
11164        cx: &mut Context<Self>,
11165    ) {
11166        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
11167    }
11168
11169    pub fn expand_excerpts_up(
11170        &mut self,
11171        action: &ExpandExcerptsUp,
11172        _: &mut Window,
11173        cx: &mut Context<Self>,
11174    ) {
11175        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
11176    }
11177
11178    pub fn expand_excerpts_for_direction(
11179        &mut self,
11180        lines: u32,
11181        direction: ExpandExcerptDirection,
11182
11183        cx: &mut Context<Self>,
11184    ) {
11185        let selections = self.selections.disjoint_anchors();
11186
11187        let lines = if lines == 0 {
11188            EditorSettings::get_global(cx).expand_excerpt_lines
11189        } else {
11190            lines
11191        };
11192
11193        self.buffer.update(cx, |buffer, cx| {
11194            let snapshot = buffer.snapshot(cx);
11195            let mut excerpt_ids = selections
11196                .iter()
11197                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
11198                .collect::<Vec<_>>();
11199            excerpt_ids.sort();
11200            excerpt_ids.dedup();
11201            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
11202        })
11203    }
11204
11205    pub fn expand_excerpt(
11206        &mut self,
11207        excerpt: ExcerptId,
11208        direction: ExpandExcerptDirection,
11209        cx: &mut Context<Self>,
11210    ) {
11211        let lines = EditorSettings::get_global(cx).expand_excerpt_lines;
11212        self.buffer.update(cx, |buffer, cx| {
11213            buffer.expand_excerpts([excerpt], lines, direction, cx)
11214        })
11215    }
11216
11217    pub fn go_to_singleton_buffer_point(
11218        &mut self,
11219        point: Point,
11220        window: &mut Window,
11221        cx: &mut Context<Self>,
11222    ) {
11223        self.go_to_singleton_buffer_range(point..point, window, cx);
11224    }
11225
11226    pub fn go_to_singleton_buffer_range(
11227        &mut self,
11228        range: Range<Point>,
11229        window: &mut Window,
11230        cx: &mut Context<Self>,
11231    ) {
11232        let multibuffer = self.buffer().read(cx);
11233        let Some(buffer) = multibuffer.as_singleton() else {
11234            return;
11235        };
11236        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
11237            return;
11238        };
11239        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
11240            return;
11241        };
11242        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
11243            s.select_anchor_ranges([start..end])
11244        });
11245    }
11246
11247    fn go_to_diagnostic(
11248        &mut self,
11249        _: &GoToDiagnostic,
11250        window: &mut Window,
11251        cx: &mut Context<Self>,
11252    ) {
11253        self.go_to_diagnostic_impl(Direction::Next, window, cx)
11254    }
11255
11256    fn go_to_prev_diagnostic(
11257        &mut self,
11258        _: &GoToPrevDiagnostic,
11259        window: &mut Window,
11260        cx: &mut Context<Self>,
11261    ) {
11262        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
11263    }
11264
11265    pub fn go_to_diagnostic_impl(
11266        &mut self,
11267        direction: Direction,
11268        window: &mut Window,
11269        cx: &mut Context<Self>,
11270    ) {
11271        let buffer = self.buffer.read(cx).snapshot(cx);
11272        let selection = self.selections.newest::<usize>(cx);
11273
11274        // If there is an active Diagnostic Popover jump to its diagnostic instead.
11275        if direction == Direction::Next {
11276            if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
11277                let Some(buffer_id) = popover.local_diagnostic.range.start.buffer_id else {
11278                    return;
11279                };
11280                self.activate_diagnostics(
11281                    buffer_id,
11282                    popover.local_diagnostic.diagnostic.group_id,
11283                    window,
11284                    cx,
11285                );
11286                if let Some(active_diagnostics) = self.active_diagnostics.as_ref() {
11287                    let primary_range_start = active_diagnostics.primary_range.start;
11288                    self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11289                        let mut new_selection = s.newest_anchor().clone();
11290                        new_selection.collapse_to(primary_range_start, SelectionGoal::None);
11291                        s.select_anchors(vec![new_selection.clone()]);
11292                    });
11293                    self.refresh_inline_completion(false, true, window, cx);
11294                }
11295                return;
11296            }
11297        }
11298
11299        let active_group_id = self
11300            .active_diagnostics
11301            .as_ref()
11302            .map(|active_group| active_group.group_id);
11303        let active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
11304            active_diagnostics
11305                .primary_range
11306                .to_offset(&buffer)
11307                .to_inclusive()
11308        });
11309        let search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
11310            if active_primary_range.contains(&selection.head()) {
11311                *active_primary_range.start()
11312            } else {
11313                selection.head()
11314            }
11315        } else {
11316            selection.head()
11317        };
11318
11319        let snapshot = self.snapshot(window, cx);
11320        let primary_diagnostics_before = buffer
11321            .diagnostics_in_range::<usize>(0..search_start)
11322            .filter(|entry| entry.diagnostic.is_primary)
11323            .filter(|entry| entry.range.start != entry.range.end)
11324            .filter(|entry| entry.diagnostic.severity <= DiagnosticSeverity::WARNING)
11325            .filter(|entry| !snapshot.intersects_fold(entry.range.start))
11326            .collect::<Vec<_>>();
11327        let last_same_group_diagnostic_before = active_group_id.and_then(|active_group_id| {
11328            primary_diagnostics_before
11329                .iter()
11330                .position(|entry| entry.diagnostic.group_id == active_group_id)
11331        });
11332
11333        let primary_diagnostics_after = buffer
11334            .diagnostics_in_range::<usize>(search_start..buffer.len())
11335            .filter(|entry| entry.diagnostic.is_primary)
11336            .filter(|entry| entry.range.start != entry.range.end)
11337            .filter(|entry| entry.diagnostic.severity <= DiagnosticSeverity::WARNING)
11338            .filter(|diagnostic| !snapshot.intersects_fold(diagnostic.range.start))
11339            .collect::<Vec<_>>();
11340        let last_same_group_diagnostic_after = active_group_id.and_then(|active_group_id| {
11341            primary_diagnostics_after
11342                .iter()
11343                .enumerate()
11344                .rev()
11345                .find_map(|(i, entry)| {
11346                    if entry.diagnostic.group_id == active_group_id {
11347                        Some(i)
11348                    } else {
11349                        None
11350                    }
11351                })
11352        });
11353
11354        let next_primary_diagnostic = match direction {
11355            Direction::Prev => primary_diagnostics_before
11356                .iter()
11357                .take(last_same_group_diagnostic_before.unwrap_or(usize::MAX))
11358                .rev()
11359                .next(),
11360            Direction::Next => primary_diagnostics_after
11361                .iter()
11362                .skip(
11363                    last_same_group_diagnostic_after
11364                        .map(|index| index + 1)
11365                        .unwrap_or(0),
11366                )
11367                .next(),
11368        };
11369
11370        // Cycle around to the start of the buffer, potentially moving back to the start of
11371        // the currently active diagnostic.
11372        let cycle_around = || match direction {
11373            Direction::Prev => primary_diagnostics_after
11374                .iter()
11375                .rev()
11376                .chain(primary_diagnostics_before.iter().rev())
11377                .next(),
11378            Direction::Next => primary_diagnostics_before
11379                .iter()
11380                .chain(primary_diagnostics_after.iter())
11381                .next(),
11382        };
11383
11384        if let Some((primary_range, group_id)) = next_primary_diagnostic
11385            .or_else(cycle_around)
11386            .map(|entry| (&entry.range, entry.diagnostic.group_id))
11387        {
11388            let Some(buffer_id) = buffer.anchor_after(primary_range.start).buffer_id else {
11389                return;
11390            };
11391            self.activate_diagnostics(buffer_id, group_id, window, cx);
11392            if self.active_diagnostics.is_some() {
11393                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11394                    s.select(vec![Selection {
11395                        id: selection.id,
11396                        start: primary_range.start,
11397                        end: primary_range.start,
11398                        reversed: false,
11399                        goal: SelectionGoal::None,
11400                    }]);
11401                });
11402                self.refresh_inline_completion(false, true, window, cx);
11403            }
11404        }
11405    }
11406
11407    fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
11408        let snapshot = self.snapshot(window, cx);
11409        let selection = self.selections.newest::<Point>(cx);
11410        self.go_to_hunk_after_position(&snapshot, selection.head(), window, cx);
11411    }
11412
11413    fn go_to_hunk_after_position(
11414        &mut self,
11415        snapshot: &EditorSnapshot,
11416        position: Point,
11417        window: &mut Window,
11418        cx: &mut Context<Editor>,
11419    ) -> Option<MultiBufferDiffHunk> {
11420        let mut hunk = snapshot
11421            .buffer_snapshot
11422            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
11423            .find(|hunk| hunk.row_range.start.0 > position.row);
11424        if hunk.is_none() {
11425            hunk = snapshot
11426                .buffer_snapshot
11427                .diff_hunks_in_range(Point::zero()..position)
11428                .find(|hunk| hunk.row_range.end.0 < position.row)
11429        }
11430        if let Some(hunk) = &hunk {
11431            let destination = Point::new(hunk.row_range.start.0, 0);
11432            self.unfold_ranges(&[destination..destination], false, false, cx);
11433            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11434                s.select_ranges(vec![destination..destination]);
11435            });
11436        }
11437
11438        hunk
11439    }
11440
11441    fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, window: &mut Window, cx: &mut Context<Self>) {
11442        let snapshot = self.snapshot(window, cx);
11443        let selection = self.selections.newest::<Point>(cx);
11444        self.go_to_hunk_before_position(&snapshot, selection.head(), window, cx);
11445    }
11446
11447    fn go_to_hunk_before_position(
11448        &mut self,
11449        snapshot: &EditorSnapshot,
11450        position: Point,
11451        window: &mut Window,
11452        cx: &mut Context<Editor>,
11453    ) -> Option<MultiBufferDiffHunk> {
11454        let mut hunk = snapshot.buffer_snapshot.diff_hunk_before(position);
11455        if hunk.is_none() {
11456            hunk = snapshot.buffer_snapshot.diff_hunk_before(Point::MAX);
11457        }
11458        if let Some(hunk) = &hunk {
11459            let destination = Point::new(hunk.row_range.start.0, 0);
11460            self.unfold_ranges(&[destination..destination], false, false, cx);
11461            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11462                s.select_ranges(vec![destination..destination]);
11463            });
11464        }
11465
11466        hunk
11467    }
11468
11469    pub fn go_to_definition(
11470        &mut self,
11471        _: &GoToDefinition,
11472        window: &mut Window,
11473        cx: &mut Context<Self>,
11474    ) -> Task<Result<Navigated>> {
11475        let definition =
11476            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
11477        cx.spawn_in(window, |editor, mut cx| async move {
11478            if definition.await? == Navigated::Yes {
11479                return Ok(Navigated::Yes);
11480            }
11481            match editor.update_in(&mut cx, |editor, window, cx| {
11482                editor.find_all_references(&FindAllReferences, window, cx)
11483            })? {
11484                Some(references) => references.await,
11485                None => Ok(Navigated::No),
11486            }
11487        })
11488    }
11489
11490    pub fn go_to_declaration(
11491        &mut self,
11492        _: &GoToDeclaration,
11493        window: &mut Window,
11494        cx: &mut Context<Self>,
11495    ) -> Task<Result<Navigated>> {
11496        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
11497    }
11498
11499    pub fn go_to_declaration_split(
11500        &mut self,
11501        _: &GoToDeclaration,
11502        window: &mut Window,
11503        cx: &mut Context<Self>,
11504    ) -> Task<Result<Navigated>> {
11505        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
11506    }
11507
11508    pub fn go_to_implementation(
11509        &mut self,
11510        _: &GoToImplementation,
11511        window: &mut Window,
11512        cx: &mut Context<Self>,
11513    ) -> Task<Result<Navigated>> {
11514        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
11515    }
11516
11517    pub fn go_to_implementation_split(
11518        &mut self,
11519        _: &GoToImplementationSplit,
11520        window: &mut Window,
11521        cx: &mut Context<Self>,
11522    ) -> Task<Result<Navigated>> {
11523        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
11524    }
11525
11526    pub fn go_to_type_definition(
11527        &mut self,
11528        _: &GoToTypeDefinition,
11529        window: &mut Window,
11530        cx: &mut Context<Self>,
11531    ) -> Task<Result<Navigated>> {
11532        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
11533    }
11534
11535    pub fn go_to_definition_split(
11536        &mut self,
11537        _: &GoToDefinitionSplit,
11538        window: &mut Window,
11539        cx: &mut Context<Self>,
11540    ) -> Task<Result<Navigated>> {
11541        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
11542    }
11543
11544    pub fn go_to_type_definition_split(
11545        &mut self,
11546        _: &GoToTypeDefinitionSplit,
11547        window: &mut Window,
11548        cx: &mut Context<Self>,
11549    ) -> Task<Result<Navigated>> {
11550        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
11551    }
11552
11553    fn go_to_definition_of_kind(
11554        &mut self,
11555        kind: GotoDefinitionKind,
11556        split: bool,
11557        window: &mut Window,
11558        cx: &mut Context<Self>,
11559    ) -> Task<Result<Navigated>> {
11560        let Some(provider) = self.semantics_provider.clone() else {
11561            return Task::ready(Ok(Navigated::No));
11562        };
11563        let head = self.selections.newest::<usize>(cx).head();
11564        let buffer = self.buffer.read(cx);
11565        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
11566            text_anchor
11567        } else {
11568            return Task::ready(Ok(Navigated::No));
11569        };
11570
11571        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
11572            return Task::ready(Ok(Navigated::No));
11573        };
11574
11575        cx.spawn_in(window, |editor, mut cx| async move {
11576            let definitions = definitions.await?;
11577            let navigated = editor
11578                .update_in(&mut cx, |editor, window, cx| {
11579                    editor.navigate_to_hover_links(
11580                        Some(kind),
11581                        definitions
11582                            .into_iter()
11583                            .filter(|location| {
11584                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
11585                            })
11586                            .map(HoverLink::Text)
11587                            .collect::<Vec<_>>(),
11588                        split,
11589                        window,
11590                        cx,
11591                    )
11592                })?
11593                .await?;
11594            anyhow::Ok(navigated)
11595        })
11596    }
11597
11598    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
11599        let selection = self.selections.newest_anchor();
11600        let head = selection.head();
11601        let tail = selection.tail();
11602
11603        let Some((buffer, start_position)) =
11604            self.buffer.read(cx).text_anchor_for_position(head, cx)
11605        else {
11606            return;
11607        };
11608
11609        let end_position = if head != tail {
11610            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
11611                return;
11612            };
11613            Some(pos)
11614        } else {
11615            None
11616        };
11617
11618        let url_finder = cx.spawn_in(window, |editor, mut cx| async move {
11619            let url = if let Some(end_pos) = end_position {
11620                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
11621            } else {
11622                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
11623            };
11624
11625            if let Some(url) = url {
11626                editor.update(&mut cx, |_, cx| {
11627                    cx.open_url(&url);
11628                })
11629            } else {
11630                Ok(())
11631            }
11632        });
11633
11634        url_finder.detach();
11635    }
11636
11637    pub fn open_selected_filename(
11638        &mut self,
11639        _: &OpenSelectedFilename,
11640        window: &mut Window,
11641        cx: &mut Context<Self>,
11642    ) {
11643        let Some(workspace) = self.workspace() else {
11644            return;
11645        };
11646
11647        let position = self.selections.newest_anchor().head();
11648
11649        let Some((buffer, buffer_position)) =
11650            self.buffer.read(cx).text_anchor_for_position(position, cx)
11651        else {
11652            return;
11653        };
11654
11655        let project = self.project.clone();
11656
11657        cx.spawn_in(window, |_, mut cx| async move {
11658            let result = find_file(&buffer, project, buffer_position, &mut cx).await;
11659
11660            if let Some((_, path)) = result {
11661                workspace
11662                    .update_in(&mut cx, |workspace, window, cx| {
11663                        workspace.open_resolved_path(path, window, cx)
11664                    })?
11665                    .await?;
11666            }
11667            anyhow::Ok(())
11668        })
11669        .detach();
11670    }
11671
11672    pub(crate) fn navigate_to_hover_links(
11673        &mut self,
11674        kind: Option<GotoDefinitionKind>,
11675        mut definitions: Vec<HoverLink>,
11676        split: bool,
11677        window: &mut Window,
11678        cx: &mut Context<Editor>,
11679    ) -> Task<Result<Navigated>> {
11680        // If there is one definition, just open it directly
11681        if definitions.len() == 1 {
11682            let definition = definitions.pop().unwrap();
11683
11684            enum TargetTaskResult {
11685                Location(Option<Location>),
11686                AlreadyNavigated,
11687            }
11688
11689            let target_task = match definition {
11690                HoverLink::Text(link) => {
11691                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
11692                }
11693                HoverLink::InlayHint(lsp_location, server_id) => {
11694                    let computation =
11695                        self.compute_target_location(lsp_location, server_id, window, cx);
11696                    cx.background_spawn(async move {
11697                        let location = computation.await?;
11698                        Ok(TargetTaskResult::Location(location))
11699                    })
11700                }
11701                HoverLink::Url(url) => {
11702                    cx.open_url(&url);
11703                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
11704                }
11705                HoverLink::File(path) => {
11706                    if let Some(workspace) = self.workspace() {
11707                        cx.spawn_in(window, |_, mut cx| async move {
11708                            workspace
11709                                .update_in(&mut cx, |workspace, window, cx| {
11710                                    workspace.open_resolved_path(path, window, cx)
11711                                })?
11712                                .await
11713                                .map(|_| TargetTaskResult::AlreadyNavigated)
11714                        })
11715                    } else {
11716                        Task::ready(Ok(TargetTaskResult::Location(None)))
11717                    }
11718                }
11719            };
11720            cx.spawn_in(window, |editor, mut cx| async move {
11721                let target = match target_task.await.context("target resolution task")? {
11722                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
11723                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
11724                    TargetTaskResult::Location(Some(target)) => target,
11725                };
11726
11727                editor.update_in(&mut cx, |editor, window, cx| {
11728                    let Some(workspace) = editor.workspace() else {
11729                        return Navigated::No;
11730                    };
11731                    let pane = workspace.read(cx).active_pane().clone();
11732
11733                    let range = target.range.to_point(target.buffer.read(cx));
11734                    let range = editor.range_for_match(&range);
11735                    let range = collapse_multiline_range(range);
11736
11737                    if !split
11738                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
11739                    {
11740                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
11741                    } else {
11742                        window.defer(cx, move |window, cx| {
11743                            let target_editor: Entity<Self> =
11744                                workspace.update(cx, |workspace, cx| {
11745                                    let pane = if split {
11746                                        workspace.adjacent_pane(window, cx)
11747                                    } else {
11748                                        workspace.active_pane().clone()
11749                                    };
11750
11751                                    workspace.open_project_item(
11752                                        pane,
11753                                        target.buffer.clone(),
11754                                        true,
11755                                        true,
11756                                        window,
11757                                        cx,
11758                                    )
11759                                });
11760                            target_editor.update(cx, |target_editor, cx| {
11761                                // When selecting a definition in a different buffer, disable the nav history
11762                                // to avoid creating a history entry at the previous cursor location.
11763                                pane.update(cx, |pane, _| pane.disable_history());
11764                                target_editor.go_to_singleton_buffer_range(range, window, cx);
11765                                pane.update(cx, |pane, _| pane.enable_history());
11766                            });
11767                        });
11768                    }
11769                    Navigated::Yes
11770                })
11771            })
11772        } else if !definitions.is_empty() {
11773            cx.spawn_in(window, |editor, mut cx| async move {
11774                let (title, location_tasks, workspace) = editor
11775                    .update_in(&mut cx, |editor, window, cx| {
11776                        let tab_kind = match kind {
11777                            Some(GotoDefinitionKind::Implementation) => "Implementations",
11778                            _ => "Definitions",
11779                        };
11780                        let title = definitions
11781                            .iter()
11782                            .find_map(|definition| match definition {
11783                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
11784                                    let buffer = origin.buffer.read(cx);
11785                                    format!(
11786                                        "{} for {}",
11787                                        tab_kind,
11788                                        buffer
11789                                            .text_for_range(origin.range.clone())
11790                                            .collect::<String>()
11791                                    )
11792                                }),
11793                                HoverLink::InlayHint(_, _) => None,
11794                                HoverLink::Url(_) => None,
11795                                HoverLink::File(_) => None,
11796                            })
11797                            .unwrap_or(tab_kind.to_string());
11798                        let location_tasks = definitions
11799                            .into_iter()
11800                            .map(|definition| match definition {
11801                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
11802                                HoverLink::InlayHint(lsp_location, server_id) => editor
11803                                    .compute_target_location(lsp_location, server_id, window, cx),
11804                                HoverLink::Url(_) => Task::ready(Ok(None)),
11805                                HoverLink::File(_) => Task::ready(Ok(None)),
11806                            })
11807                            .collect::<Vec<_>>();
11808                        (title, location_tasks, editor.workspace().clone())
11809                    })
11810                    .context("location tasks preparation")?;
11811
11812                let locations = future::join_all(location_tasks)
11813                    .await
11814                    .into_iter()
11815                    .filter_map(|location| location.transpose())
11816                    .collect::<Result<_>>()
11817                    .context("location tasks")?;
11818
11819                let Some(workspace) = workspace else {
11820                    return Ok(Navigated::No);
11821                };
11822                let opened = workspace
11823                    .update_in(&mut cx, |workspace, window, cx| {
11824                        Self::open_locations_in_multibuffer(
11825                            workspace,
11826                            locations,
11827                            title,
11828                            split,
11829                            MultibufferSelectionMode::First,
11830                            window,
11831                            cx,
11832                        )
11833                    })
11834                    .ok();
11835
11836                anyhow::Ok(Navigated::from_bool(opened.is_some()))
11837            })
11838        } else {
11839            Task::ready(Ok(Navigated::No))
11840        }
11841    }
11842
11843    fn compute_target_location(
11844        &self,
11845        lsp_location: lsp::Location,
11846        server_id: LanguageServerId,
11847        window: &mut Window,
11848        cx: &mut Context<Self>,
11849    ) -> Task<anyhow::Result<Option<Location>>> {
11850        let Some(project) = self.project.clone() else {
11851            return Task::ready(Ok(None));
11852        };
11853
11854        cx.spawn_in(window, move |editor, mut cx| async move {
11855            let location_task = editor.update(&mut cx, |_, cx| {
11856                project.update(cx, |project, cx| {
11857                    let language_server_name = project
11858                        .language_server_statuses(cx)
11859                        .find(|(id, _)| server_id == *id)
11860                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
11861                    language_server_name.map(|language_server_name| {
11862                        project.open_local_buffer_via_lsp(
11863                            lsp_location.uri.clone(),
11864                            server_id,
11865                            language_server_name,
11866                            cx,
11867                        )
11868                    })
11869                })
11870            })?;
11871            let location = match location_task {
11872                Some(task) => Some({
11873                    let target_buffer_handle = task.await.context("open local buffer")?;
11874                    let range = target_buffer_handle.update(&mut cx, |target_buffer, _| {
11875                        let target_start = target_buffer
11876                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
11877                        let target_end = target_buffer
11878                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
11879                        target_buffer.anchor_after(target_start)
11880                            ..target_buffer.anchor_before(target_end)
11881                    })?;
11882                    Location {
11883                        buffer: target_buffer_handle,
11884                        range,
11885                    }
11886                }),
11887                None => None,
11888            };
11889            Ok(location)
11890        })
11891    }
11892
11893    pub fn find_all_references(
11894        &mut self,
11895        _: &FindAllReferences,
11896        window: &mut Window,
11897        cx: &mut Context<Self>,
11898    ) -> Option<Task<Result<Navigated>>> {
11899        let selection = self.selections.newest::<usize>(cx);
11900        let multi_buffer = self.buffer.read(cx);
11901        let head = selection.head();
11902
11903        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
11904        let head_anchor = multi_buffer_snapshot.anchor_at(
11905            head,
11906            if head < selection.tail() {
11907                Bias::Right
11908            } else {
11909                Bias::Left
11910            },
11911        );
11912
11913        match self
11914            .find_all_references_task_sources
11915            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
11916        {
11917            Ok(_) => {
11918                log::info!(
11919                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
11920                );
11921                return None;
11922            }
11923            Err(i) => {
11924                self.find_all_references_task_sources.insert(i, head_anchor);
11925            }
11926        }
11927
11928        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
11929        let workspace = self.workspace()?;
11930        let project = workspace.read(cx).project().clone();
11931        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
11932        Some(cx.spawn_in(window, |editor, mut cx| async move {
11933            let _cleanup = defer({
11934                let mut cx = cx.clone();
11935                move || {
11936                    let _ = editor.update(&mut cx, |editor, _| {
11937                        if let Ok(i) =
11938                            editor
11939                                .find_all_references_task_sources
11940                                .binary_search_by(|anchor| {
11941                                    anchor.cmp(&head_anchor, &multi_buffer_snapshot)
11942                                })
11943                        {
11944                            editor.find_all_references_task_sources.remove(i);
11945                        }
11946                    });
11947                }
11948            });
11949
11950            let locations = references.await?;
11951            if locations.is_empty() {
11952                return anyhow::Ok(Navigated::No);
11953            }
11954
11955            workspace.update_in(&mut cx, |workspace, window, cx| {
11956                let title = locations
11957                    .first()
11958                    .as_ref()
11959                    .map(|location| {
11960                        let buffer = location.buffer.read(cx);
11961                        format!(
11962                            "References to `{}`",
11963                            buffer
11964                                .text_for_range(location.range.clone())
11965                                .collect::<String>()
11966                        )
11967                    })
11968                    .unwrap();
11969                Self::open_locations_in_multibuffer(
11970                    workspace,
11971                    locations,
11972                    title,
11973                    false,
11974                    MultibufferSelectionMode::First,
11975                    window,
11976                    cx,
11977                );
11978                Navigated::Yes
11979            })
11980        }))
11981    }
11982
11983    /// Opens a multibuffer with the given project locations in it
11984    pub fn open_locations_in_multibuffer(
11985        workspace: &mut Workspace,
11986        mut locations: Vec<Location>,
11987        title: String,
11988        split: bool,
11989        multibuffer_selection_mode: MultibufferSelectionMode,
11990        window: &mut Window,
11991        cx: &mut Context<Workspace>,
11992    ) {
11993        // If there are multiple definitions, open them in a multibuffer
11994        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
11995        let mut locations = locations.into_iter().peekable();
11996        let mut ranges = Vec::new();
11997        let capability = workspace.project().read(cx).capability();
11998
11999        let excerpt_buffer = cx.new(|cx| {
12000            let mut multibuffer = MultiBuffer::new(capability);
12001            while let Some(location) = locations.next() {
12002                let buffer = location.buffer.read(cx);
12003                let mut ranges_for_buffer = Vec::new();
12004                let range = location.range.to_offset(buffer);
12005                ranges_for_buffer.push(range.clone());
12006
12007                while let Some(next_location) = locations.peek() {
12008                    if next_location.buffer == location.buffer {
12009                        ranges_for_buffer.push(next_location.range.to_offset(buffer));
12010                        locations.next();
12011                    } else {
12012                        break;
12013                    }
12014                }
12015
12016                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
12017                ranges.extend(multibuffer.push_excerpts_with_context_lines(
12018                    location.buffer.clone(),
12019                    ranges_for_buffer,
12020                    DEFAULT_MULTIBUFFER_CONTEXT,
12021                    cx,
12022                ))
12023            }
12024
12025            multibuffer.with_title(title)
12026        });
12027
12028        let editor = cx.new(|cx| {
12029            Editor::for_multibuffer(
12030                excerpt_buffer,
12031                Some(workspace.project().clone()),
12032                true,
12033                window,
12034                cx,
12035            )
12036        });
12037        editor.update(cx, |editor, cx| {
12038            match multibuffer_selection_mode {
12039                MultibufferSelectionMode::First => {
12040                    if let Some(first_range) = ranges.first() {
12041                        editor.change_selections(None, window, cx, |selections| {
12042                            selections.clear_disjoint();
12043                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
12044                        });
12045                    }
12046                    editor.highlight_background::<Self>(
12047                        &ranges,
12048                        |theme| theme.editor_highlighted_line_background,
12049                        cx,
12050                    );
12051                }
12052                MultibufferSelectionMode::All => {
12053                    editor.change_selections(None, window, cx, |selections| {
12054                        selections.clear_disjoint();
12055                        selections.select_anchor_ranges(ranges);
12056                    });
12057                }
12058            }
12059            editor.register_buffers_with_language_servers(cx);
12060        });
12061
12062        let item = Box::new(editor);
12063        let item_id = item.item_id();
12064
12065        if split {
12066            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
12067        } else {
12068            let destination_index = workspace.active_pane().update(cx, |pane, cx| {
12069                if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
12070                    pane.close_current_preview_item(window, cx)
12071                } else {
12072                    None
12073                }
12074            });
12075            workspace.add_item_to_active_pane(item.clone(), destination_index, true, window, cx);
12076        }
12077        workspace.active_pane().update(cx, |pane, cx| {
12078            pane.set_preview_item_id(Some(item_id), cx);
12079        });
12080    }
12081
12082    pub fn rename(
12083        &mut self,
12084        _: &Rename,
12085        window: &mut Window,
12086        cx: &mut Context<Self>,
12087    ) -> Option<Task<Result<()>>> {
12088        use language::ToOffset as _;
12089
12090        let provider = self.semantics_provider.clone()?;
12091        let selection = self.selections.newest_anchor().clone();
12092        let (cursor_buffer, cursor_buffer_position) = self
12093            .buffer
12094            .read(cx)
12095            .text_anchor_for_position(selection.head(), cx)?;
12096        let (tail_buffer, cursor_buffer_position_end) = self
12097            .buffer
12098            .read(cx)
12099            .text_anchor_for_position(selection.tail(), cx)?;
12100        if tail_buffer != cursor_buffer {
12101            return None;
12102        }
12103
12104        let snapshot = cursor_buffer.read(cx).snapshot();
12105        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
12106        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
12107        let prepare_rename = provider
12108            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
12109            .unwrap_or_else(|| Task::ready(Ok(None)));
12110        drop(snapshot);
12111
12112        Some(cx.spawn_in(window, |this, mut cx| async move {
12113            let rename_range = if let Some(range) = prepare_rename.await? {
12114                Some(range)
12115            } else {
12116                this.update(&mut cx, |this, cx| {
12117                    let buffer = this.buffer.read(cx).snapshot(cx);
12118                    let mut buffer_highlights = this
12119                        .document_highlights_for_position(selection.head(), &buffer)
12120                        .filter(|highlight| {
12121                            highlight.start.excerpt_id == selection.head().excerpt_id
12122                                && highlight.end.excerpt_id == selection.head().excerpt_id
12123                        });
12124                    buffer_highlights
12125                        .next()
12126                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
12127                })?
12128            };
12129            if let Some(rename_range) = rename_range {
12130                this.update_in(&mut cx, |this, window, cx| {
12131                    let snapshot = cursor_buffer.read(cx).snapshot();
12132                    let rename_buffer_range = rename_range.to_offset(&snapshot);
12133                    let cursor_offset_in_rename_range =
12134                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
12135                    let cursor_offset_in_rename_range_end =
12136                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
12137
12138                    this.take_rename(false, window, cx);
12139                    let buffer = this.buffer.read(cx).read(cx);
12140                    let cursor_offset = selection.head().to_offset(&buffer);
12141                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
12142                    let rename_end = rename_start + rename_buffer_range.len();
12143                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
12144                    let mut old_highlight_id = None;
12145                    let old_name: Arc<str> = buffer
12146                        .chunks(rename_start..rename_end, true)
12147                        .map(|chunk| {
12148                            if old_highlight_id.is_none() {
12149                                old_highlight_id = chunk.syntax_highlight_id;
12150                            }
12151                            chunk.text
12152                        })
12153                        .collect::<String>()
12154                        .into();
12155
12156                    drop(buffer);
12157
12158                    // Position the selection in the rename editor so that it matches the current selection.
12159                    this.show_local_selections = false;
12160                    let rename_editor = cx.new(|cx| {
12161                        let mut editor = Editor::single_line(window, cx);
12162                        editor.buffer.update(cx, |buffer, cx| {
12163                            buffer.edit([(0..0, old_name.clone())], None, cx)
12164                        });
12165                        let rename_selection_range = match cursor_offset_in_rename_range
12166                            .cmp(&cursor_offset_in_rename_range_end)
12167                        {
12168                            Ordering::Equal => {
12169                                editor.select_all(&SelectAll, window, cx);
12170                                return editor;
12171                            }
12172                            Ordering::Less => {
12173                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
12174                            }
12175                            Ordering::Greater => {
12176                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
12177                            }
12178                        };
12179                        if rename_selection_range.end > old_name.len() {
12180                            editor.select_all(&SelectAll, window, cx);
12181                        } else {
12182                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12183                                s.select_ranges([rename_selection_range]);
12184                            });
12185                        }
12186                        editor
12187                    });
12188                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
12189                        if e == &EditorEvent::Focused {
12190                            cx.emit(EditorEvent::FocusedIn)
12191                        }
12192                    })
12193                    .detach();
12194
12195                    let write_highlights =
12196                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
12197                    let read_highlights =
12198                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
12199                    let ranges = write_highlights
12200                        .iter()
12201                        .flat_map(|(_, ranges)| ranges.iter())
12202                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
12203                        .cloned()
12204                        .collect();
12205
12206                    this.highlight_text::<Rename>(
12207                        ranges,
12208                        HighlightStyle {
12209                            fade_out: Some(0.6),
12210                            ..Default::default()
12211                        },
12212                        cx,
12213                    );
12214                    let rename_focus_handle = rename_editor.focus_handle(cx);
12215                    window.focus(&rename_focus_handle);
12216                    let block_id = this.insert_blocks(
12217                        [BlockProperties {
12218                            style: BlockStyle::Flex,
12219                            placement: BlockPlacement::Below(range.start),
12220                            height: 1,
12221                            render: Arc::new({
12222                                let rename_editor = rename_editor.clone();
12223                                move |cx: &mut BlockContext| {
12224                                    let mut text_style = cx.editor_style.text.clone();
12225                                    if let Some(highlight_style) = old_highlight_id
12226                                        .and_then(|h| h.style(&cx.editor_style.syntax))
12227                                    {
12228                                        text_style = text_style.highlight(highlight_style);
12229                                    }
12230                                    div()
12231                                        .block_mouse_down()
12232                                        .pl(cx.anchor_x)
12233                                        .child(EditorElement::new(
12234                                            &rename_editor,
12235                                            EditorStyle {
12236                                                background: cx.theme().system().transparent,
12237                                                local_player: cx.editor_style.local_player,
12238                                                text: text_style,
12239                                                scrollbar_width: cx.editor_style.scrollbar_width,
12240                                                syntax: cx.editor_style.syntax.clone(),
12241                                                status: cx.editor_style.status.clone(),
12242                                                inlay_hints_style: HighlightStyle {
12243                                                    font_weight: Some(FontWeight::BOLD),
12244                                                    ..make_inlay_hints_style(cx.app)
12245                                                },
12246                                                inline_completion_styles: make_suggestion_styles(
12247                                                    cx.app,
12248                                                ),
12249                                                ..EditorStyle::default()
12250                                            },
12251                                        ))
12252                                        .into_any_element()
12253                                }
12254                            }),
12255                            priority: 0,
12256                        }],
12257                        Some(Autoscroll::fit()),
12258                        cx,
12259                    )[0];
12260                    this.pending_rename = Some(RenameState {
12261                        range,
12262                        old_name,
12263                        editor: rename_editor,
12264                        block_id,
12265                    });
12266                })?;
12267            }
12268
12269            Ok(())
12270        }))
12271    }
12272
12273    pub fn confirm_rename(
12274        &mut self,
12275        _: &ConfirmRename,
12276        window: &mut Window,
12277        cx: &mut Context<Self>,
12278    ) -> Option<Task<Result<()>>> {
12279        let rename = self.take_rename(false, window, cx)?;
12280        let workspace = self.workspace()?.downgrade();
12281        let (buffer, start) = self
12282            .buffer
12283            .read(cx)
12284            .text_anchor_for_position(rename.range.start, cx)?;
12285        let (end_buffer, _) = self
12286            .buffer
12287            .read(cx)
12288            .text_anchor_for_position(rename.range.end, cx)?;
12289        if buffer != end_buffer {
12290            return None;
12291        }
12292
12293        let old_name = rename.old_name;
12294        let new_name = rename.editor.read(cx).text(cx);
12295
12296        let rename = self.semantics_provider.as_ref()?.perform_rename(
12297            &buffer,
12298            start,
12299            new_name.clone(),
12300            cx,
12301        )?;
12302
12303        Some(cx.spawn_in(window, |editor, mut cx| async move {
12304            let project_transaction = rename.await?;
12305            Self::open_project_transaction(
12306                &editor,
12307                workspace,
12308                project_transaction,
12309                format!("Rename: {}{}", old_name, new_name),
12310                cx.clone(),
12311            )
12312            .await?;
12313
12314            editor.update(&mut cx, |editor, cx| {
12315                editor.refresh_document_highlights(cx);
12316            })?;
12317            Ok(())
12318        }))
12319    }
12320
12321    fn take_rename(
12322        &mut self,
12323        moving_cursor: bool,
12324        window: &mut Window,
12325        cx: &mut Context<Self>,
12326    ) -> Option<RenameState> {
12327        let rename = self.pending_rename.take()?;
12328        if rename.editor.focus_handle(cx).is_focused(window) {
12329            window.focus(&self.focus_handle);
12330        }
12331
12332        self.remove_blocks(
12333            [rename.block_id].into_iter().collect(),
12334            Some(Autoscroll::fit()),
12335            cx,
12336        );
12337        self.clear_highlights::<Rename>(cx);
12338        self.show_local_selections = true;
12339
12340        if moving_cursor {
12341            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
12342                editor.selections.newest::<usize>(cx).head()
12343            });
12344
12345            // Update the selection to match the position of the selection inside
12346            // the rename editor.
12347            let snapshot = self.buffer.read(cx).read(cx);
12348            let rename_range = rename.range.to_offset(&snapshot);
12349            let cursor_in_editor = snapshot
12350                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
12351                .min(rename_range.end);
12352            drop(snapshot);
12353
12354            self.change_selections(None, window, cx, |s| {
12355                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
12356            });
12357        } else {
12358            self.refresh_document_highlights(cx);
12359        }
12360
12361        Some(rename)
12362    }
12363
12364    pub fn pending_rename(&self) -> Option<&RenameState> {
12365        self.pending_rename.as_ref()
12366    }
12367
12368    fn format(
12369        &mut self,
12370        _: &Format,
12371        window: &mut Window,
12372        cx: &mut Context<Self>,
12373    ) -> Option<Task<Result<()>>> {
12374        let project = match &self.project {
12375            Some(project) => project.clone(),
12376            None => return None,
12377        };
12378
12379        Some(self.perform_format(
12380            project,
12381            FormatTrigger::Manual,
12382            FormatTarget::Buffers,
12383            window,
12384            cx,
12385        ))
12386    }
12387
12388    fn format_selections(
12389        &mut self,
12390        _: &FormatSelections,
12391        window: &mut Window,
12392        cx: &mut Context<Self>,
12393    ) -> Option<Task<Result<()>>> {
12394        let project = match &self.project {
12395            Some(project) => project.clone(),
12396            None => return None,
12397        };
12398
12399        let ranges = self
12400            .selections
12401            .all_adjusted(cx)
12402            .into_iter()
12403            .map(|selection| selection.range())
12404            .collect_vec();
12405
12406        Some(self.perform_format(
12407            project,
12408            FormatTrigger::Manual,
12409            FormatTarget::Ranges(ranges),
12410            window,
12411            cx,
12412        ))
12413    }
12414
12415    fn perform_format(
12416        &mut self,
12417        project: Entity<Project>,
12418        trigger: FormatTrigger,
12419        target: FormatTarget,
12420        window: &mut Window,
12421        cx: &mut Context<Self>,
12422    ) -> Task<Result<()>> {
12423        let buffer = self.buffer.clone();
12424        let (buffers, target) = match target {
12425            FormatTarget::Buffers => {
12426                let mut buffers = buffer.read(cx).all_buffers();
12427                if trigger == FormatTrigger::Save {
12428                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
12429                }
12430                (buffers, LspFormatTarget::Buffers)
12431            }
12432            FormatTarget::Ranges(selection_ranges) => {
12433                let multi_buffer = buffer.read(cx);
12434                let snapshot = multi_buffer.read(cx);
12435                let mut buffers = HashSet::default();
12436                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
12437                    BTreeMap::new();
12438                for selection_range in selection_ranges {
12439                    for (buffer, buffer_range, _) in
12440                        snapshot.range_to_buffer_ranges(selection_range)
12441                    {
12442                        let buffer_id = buffer.remote_id();
12443                        let start = buffer.anchor_before(buffer_range.start);
12444                        let end = buffer.anchor_after(buffer_range.end);
12445                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
12446                        buffer_id_to_ranges
12447                            .entry(buffer_id)
12448                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
12449                            .or_insert_with(|| vec![start..end]);
12450                    }
12451                }
12452                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
12453            }
12454        };
12455
12456        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
12457        let format = project.update(cx, |project, cx| {
12458            project.format(buffers, target, true, trigger, cx)
12459        });
12460
12461        cx.spawn_in(window, |_, mut cx| async move {
12462            let transaction = futures::select_biased! {
12463                () = timeout => {
12464                    log::warn!("timed out waiting for formatting");
12465                    None
12466                }
12467                transaction = format.log_err().fuse() => transaction,
12468            };
12469
12470            buffer
12471                .update(&mut cx, |buffer, cx| {
12472                    if let Some(transaction) = transaction {
12473                        if !buffer.is_singleton() {
12474                            buffer.push_transaction(&transaction.0, cx);
12475                        }
12476                    }
12477
12478                    cx.notify();
12479                })
12480                .ok();
12481
12482            Ok(())
12483        })
12484    }
12485
12486    fn restart_language_server(
12487        &mut self,
12488        _: &RestartLanguageServer,
12489        _: &mut Window,
12490        cx: &mut Context<Self>,
12491    ) {
12492        if let Some(project) = self.project.clone() {
12493            self.buffer.update(cx, |multi_buffer, cx| {
12494                project.update(cx, |project, cx| {
12495                    project.restart_language_servers_for_buffers(
12496                        multi_buffer.all_buffers().into_iter().collect(),
12497                        cx,
12498                    );
12499                });
12500            })
12501        }
12502    }
12503
12504    fn cancel_language_server_work(
12505        workspace: &mut Workspace,
12506        _: &actions::CancelLanguageServerWork,
12507        _: &mut Window,
12508        cx: &mut Context<Workspace>,
12509    ) {
12510        let project = workspace.project();
12511        let buffers = workspace
12512            .active_item(cx)
12513            .and_then(|item| item.act_as::<Editor>(cx))
12514            .map_or(HashSet::default(), |editor| {
12515                editor.read(cx).buffer.read(cx).all_buffers()
12516            });
12517        project.update(cx, |project, cx| {
12518            project.cancel_language_server_work_for_buffers(buffers, cx);
12519        });
12520    }
12521
12522    fn show_character_palette(
12523        &mut self,
12524        _: &ShowCharacterPalette,
12525        window: &mut Window,
12526        _: &mut Context<Self>,
12527    ) {
12528        window.show_character_palette();
12529    }
12530
12531    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
12532        if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
12533            let buffer = self.buffer.read(cx).snapshot(cx);
12534            let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
12535            let primary_range_end = active_diagnostics.primary_range.end.to_offset(&buffer);
12536            let is_valid = buffer
12537                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
12538                .any(|entry| {
12539                    entry.diagnostic.is_primary
12540                        && !entry.range.is_empty()
12541                        && entry.range.start == primary_range_start
12542                        && entry.diagnostic.message == active_diagnostics.primary_message
12543                });
12544
12545            if is_valid != active_diagnostics.is_valid {
12546                active_diagnostics.is_valid = is_valid;
12547                if is_valid {
12548                    let mut new_styles = HashMap::default();
12549                    for (block_id, diagnostic) in &active_diagnostics.blocks {
12550                        new_styles.insert(
12551                            *block_id,
12552                            diagnostic_block_renderer(diagnostic.clone(), None, true),
12553                        );
12554                    }
12555                    self.display_map.update(cx, |display_map, _cx| {
12556                        display_map.replace_blocks(new_styles);
12557                    });
12558                } else {
12559                    self.dismiss_diagnostics(cx);
12560                }
12561            }
12562        }
12563    }
12564
12565    fn activate_diagnostics(
12566        &mut self,
12567        buffer_id: BufferId,
12568        group_id: usize,
12569        window: &mut Window,
12570        cx: &mut Context<Self>,
12571    ) {
12572        self.dismiss_diagnostics(cx);
12573        let snapshot = self.snapshot(window, cx);
12574        self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
12575            let buffer = self.buffer.read(cx).snapshot(cx);
12576
12577            let mut primary_range = None;
12578            let mut primary_message = None;
12579            let diagnostic_group = buffer
12580                .diagnostic_group(buffer_id, group_id)
12581                .filter_map(|entry| {
12582                    let start = entry.range.start;
12583                    let end = entry.range.end;
12584                    if snapshot.is_line_folded(MultiBufferRow(start.row))
12585                        && (start.row == end.row
12586                            || snapshot.is_line_folded(MultiBufferRow(end.row)))
12587                    {
12588                        return None;
12589                    }
12590                    if entry.diagnostic.is_primary {
12591                        primary_range = Some(entry.range.clone());
12592                        primary_message = Some(entry.diagnostic.message.clone());
12593                    }
12594                    Some(entry)
12595                })
12596                .collect::<Vec<_>>();
12597            let primary_range = primary_range?;
12598            let primary_message = primary_message?;
12599
12600            let blocks = display_map
12601                .insert_blocks(
12602                    diagnostic_group.iter().map(|entry| {
12603                        let diagnostic = entry.diagnostic.clone();
12604                        let message_height = diagnostic.message.matches('\n').count() as u32 + 1;
12605                        BlockProperties {
12606                            style: BlockStyle::Fixed,
12607                            placement: BlockPlacement::Below(
12608                                buffer.anchor_after(entry.range.start),
12609                            ),
12610                            height: message_height,
12611                            render: diagnostic_block_renderer(diagnostic, None, true),
12612                            priority: 0,
12613                        }
12614                    }),
12615                    cx,
12616                )
12617                .into_iter()
12618                .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
12619                .collect();
12620
12621            Some(ActiveDiagnosticGroup {
12622                primary_range: buffer.anchor_before(primary_range.start)
12623                    ..buffer.anchor_after(primary_range.end),
12624                primary_message,
12625                group_id,
12626                blocks,
12627                is_valid: true,
12628            })
12629        });
12630    }
12631
12632    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
12633        if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
12634            self.display_map.update(cx, |display_map, cx| {
12635                display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
12636            });
12637            cx.notify();
12638        }
12639    }
12640
12641    /// Disable inline diagnostics rendering for this editor.
12642    pub fn disable_inline_diagnostics(&mut self) {
12643        self.inline_diagnostics_enabled = false;
12644        self.inline_diagnostics_update = Task::ready(());
12645        self.inline_diagnostics.clear();
12646    }
12647
12648    pub fn inline_diagnostics_enabled(&self) -> bool {
12649        self.inline_diagnostics_enabled
12650    }
12651
12652    pub fn show_inline_diagnostics(&self) -> bool {
12653        self.show_inline_diagnostics
12654    }
12655
12656    pub fn toggle_inline_diagnostics(
12657        &mut self,
12658        _: &ToggleInlineDiagnostics,
12659        window: &mut Window,
12660        cx: &mut Context<'_, Editor>,
12661    ) {
12662        self.show_inline_diagnostics = !self.show_inline_diagnostics;
12663        self.refresh_inline_diagnostics(false, window, cx);
12664    }
12665
12666    fn refresh_inline_diagnostics(
12667        &mut self,
12668        debounce: bool,
12669        window: &mut Window,
12670        cx: &mut Context<Self>,
12671    ) {
12672        if !self.inline_diagnostics_enabled || !self.show_inline_diagnostics {
12673            self.inline_diagnostics_update = Task::ready(());
12674            self.inline_diagnostics.clear();
12675            return;
12676        }
12677
12678        let debounce_ms = ProjectSettings::get_global(cx)
12679            .diagnostics
12680            .inline
12681            .update_debounce_ms;
12682        let debounce = if debounce && debounce_ms > 0 {
12683            Some(Duration::from_millis(debounce_ms))
12684        } else {
12685            None
12686        };
12687        self.inline_diagnostics_update = cx.spawn_in(window, |editor, mut cx| async move {
12688            if let Some(debounce) = debounce {
12689                cx.background_executor().timer(debounce).await;
12690            }
12691            let Some(snapshot) = editor
12692                .update(&mut cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
12693                .ok()
12694            else {
12695                return;
12696            };
12697
12698            let new_inline_diagnostics = cx
12699                .background_spawn(async move {
12700                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
12701                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
12702                        let message = diagnostic_entry
12703                            .diagnostic
12704                            .message
12705                            .split_once('\n')
12706                            .map(|(line, _)| line)
12707                            .map(SharedString::new)
12708                            .unwrap_or_else(|| {
12709                                SharedString::from(diagnostic_entry.diagnostic.message)
12710                            });
12711                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
12712                        let (Ok(i) | Err(i)) = inline_diagnostics
12713                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
12714                        inline_diagnostics.insert(
12715                            i,
12716                            (
12717                                start_anchor,
12718                                InlineDiagnostic {
12719                                    message,
12720                                    group_id: diagnostic_entry.diagnostic.group_id,
12721                                    start: diagnostic_entry.range.start.to_point(&snapshot),
12722                                    is_primary: diagnostic_entry.diagnostic.is_primary,
12723                                    severity: diagnostic_entry.diagnostic.severity,
12724                                },
12725                            ),
12726                        );
12727                    }
12728                    inline_diagnostics
12729                })
12730                .await;
12731
12732            editor
12733                .update(&mut cx, |editor, cx| {
12734                    editor.inline_diagnostics = new_inline_diagnostics;
12735                    cx.notify();
12736                })
12737                .ok();
12738        });
12739    }
12740
12741    pub fn set_selections_from_remote(
12742        &mut self,
12743        selections: Vec<Selection<Anchor>>,
12744        pending_selection: Option<Selection<Anchor>>,
12745        window: &mut Window,
12746        cx: &mut Context<Self>,
12747    ) {
12748        let old_cursor_position = self.selections.newest_anchor().head();
12749        self.selections.change_with(cx, |s| {
12750            s.select_anchors(selections);
12751            if let Some(pending_selection) = pending_selection {
12752                s.set_pending(pending_selection, SelectMode::Character);
12753            } else {
12754                s.clear_pending();
12755            }
12756        });
12757        self.selections_did_change(false, &old_cursor_position, true, window, cx);
12758    }
12759
12760    fn push_to_selection_history(&mut self) {
12761        self.selection_history.push(SelectionHistoryEntry {
12762            selections: self.selections.disjoint_anchors(),
12763            select_next_state: self.select_next_state.clone(),
12764            select_prev_state: self.select_prev_state.clone(),
12765            add_selections_state: self.add_selections_state.clone(),
12766        });
12767    }
12768
12769    pub fn transact(
12770        &mut self,
12771        window: &mut Window,
12772        cx: &mut Context<Self>,
12773        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
12774    ) -> Option<TransactionId> {
12775        self.start_transaction_at(Instant::now(), window, cx);
12776        update(self, window, cx);
12777        self.end_transaction_at(Instant::now(), cx)
12778    }
12779
12780    pub fn start_transaction_at(
12781        &mut self,
12782        now: Instant,
12783        window: &mut Window,
12784        cx: &mut Context<Self>,
12785    ) {
12786        self.end_selection(window, cx);
12787        if let Some(tx_id) = self
12788            .buffer
12789            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
12790        {
12791            self.selection_history
12792                .insert_transaction(tx_id, self.selections.disjoint_anchors());
12793            cx.emit(EditorEvent::TransactionBegun {
12794                transaction_id: tx_id,
12795            })
12796        }
12797    }
12798
12799    pub fn end_transaction_at(
12800        &mut self,
12801        now: Instant,
12802        cx: &mut Context<Self>,
12803    ) -> Option<TransactionId> {
12804        if let Some(transaction_id) = self
12805            .buffer
12806            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
12807        {
12808            if let Some((_, end_selections)) =
12809                self.selection_history.transaction_mut(transaction_id)
12810            {
12811                *end_selections = Some(self.selections.disjoint_anchors());
12812            } else {
12813                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
12814            }
12815
12816            cx.emit(EditorEvent::Edited { transaction_id });
12817            Some(transaction_id)
12818        } else {
12819            None
12820        }
12821    }
12822
12823    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
12824        if self.selection_mark_mode {
12825            self.change_selections(None, window, cx, |s| {
12826                s.move_with(|_, sel| {
12827                    sel.collapse_to(sel.head(), SelectionGoal::None);
12828                });
12829            })
12830        }
12831        self.selection_mark_mode = true;
12832        cx.notify();
12833    }
12834
12835    pub fn swap_selection_ends(
12836        &mut self,
12837        _: &actions::SwapSelectionEnds,
12838        window: &mut Window,
12839        cx: &mut Context<Self>,
12840    ) {
12841        self.change_selections(None, window, cx, |s| {
12842            s.move_with(|_, sel| {
12843                if sel.start != sel.end {
12844                    sel.reversed = !sel.reversed
12845                }
12846            });
12847        });
12848        self.request_autoscroll(Autoscroll::newest(), cx);
12849        cx.notify();
12850    }
12851
12852    pub fn toggle_fold(
12853        &mut self,
12854        _: &actions::ToggleFold,
12855        window: &mut Window,
12856        cx: &mut Context<Self>,
12857    ) {
12858        if self.is_singleton(cx) {
12859            let selection = self.selections.newest::<Point>(cx);
12860
12861            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12862            let range = if selection.is_empty() {
12863                let point = selection.head().to_display_point(&display_map);
12864                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
12865                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
12866                    .to_point(&display_map);
12867                start..end
12868            } else {
12869                selection.range()
12870            };
12871            if display_map.folds_in_range(range).next().is_some() {
12872                self.unfold_lines(&Default::default(), window, cx)
12873            } else {
12874                self.fold(&Default::default(), window, cx)
12875            }
12876        } else {
12877            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
12878            let buffer_ids: HashSet<_> = multi_buffer_snapshot
12879                .ranges_to_buffer_ranges(self.selections.disjoint_anchor_ranges())
12880                .map(|(snapshot, _, _)| snapshot.remote_id())
12881                .collect();
12882
12883            for buffer_id in buffer_ids {
12884                if self.is_buffer_folded(buffer_id, cx) {
12885                    self.unfold_buffer(buffer_id, cx);
12886                } else {
12887                    self.fold_buffer(buffer_id, cx);
12888                }
12889            }
12890        }
12891    }
12892
12893    pub fn toggle_fold_recursive(
12894        &mut self,
12895        _: &actions::ToggleFoldRecursive,
12896        window: &mut Window,
12897        cx: &mut Context<Self>,
12898    ) {
12899        let selection = self.selections.newest::<Point>(cx);
12900
12901        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12902        let range = if selection.is_empty() {
12903            let point = selection.head().to_display_point(&display_map);
12904            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
12905            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
12906                .to_point(&display_map);
12907            start..end
12908        } else {
12909            selection.range()
12910        };
12911        if display_map.folds_in_range(range).next().is_some() {
12912            self.unfold_recursive(&Default::default(), window, cx)
12913        } else {
12914            self.fold_recursive(&Default::default(), window, cx)
12915        }
12916    }
12917
12918    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
12919        if self.is_singleton(cx) {
12920            let mut to_fold = Vec::new();
12921            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12922            let selections = self.selections.all_adjusted(cx);
12923
12924            for selection in selections {
12925                let range = selection.range().sorted();
12926                let buffer_start_row = range.start.row;
12927
12928                if range.start.row != range.end.row {
12929                    let mut found = false;
12930                    let mut row = range.start.row;
12931                    while row <= range.end.row {
12932                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
12933                        {
12934                            found = true;
12935                            row = crease.range().end.row + 1;
12936                            to_fold.push(crease);
12937                        } else {
12938                            row += 1
12939                        }
12940                    }
12941                    if found {
12942                        continue;
12943                    }
12944                }
12945
12946                for row in (0..=range.start.row).rev() {
12947                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
12948                        if crease.range().end.row >= buffer_start_row {
12949                            to_fold.push(crease);
12950                            if row <= range.start.row {
12951                                break;
12952                            }
12953                        }
12954                    }
12955                }
12956            }
12957
12958            self.fold_creases(to_fold, true, window, cx);
12959        } else {
12960            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
12961
12962            let buffer_ids: HashSet<_> = multi_buffer_snapshot
12963                .ranges_to_buffer_ranges(self.selections.disjoint_anchor_ranges())
12964                .map(|(snapshot, _, _)| snapshot.remote_id())
12965                .collect();
12966            for buffer_id in buffer_ids {
12967                self.fold_buffer(buffer_id, cx);
12968            }
12969        }
12970    }
12971
12972    fn fold_at_level(
12973        &mut self,
12974        fold_at: &FoldAtLevel,
12975        window: &mut Window,
12976        cx: &mut Context<Self>,
12977    ) {
12978        if !self.buffer.read(cx).is_singleton() {
12979            return;
12980        }
12981
12982        let fold_at_level = fold_at.0;
12983        let snapshot = self.buffer.read(cx).snapshot(cx);
12984        let mut to_fold = Vec::new();
12985        let mut stack = vec![(0, snapshot.max_row().0, 1)];
12986
12987        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
12988            while start_row < end_row {
12989                match self
12990                    .snapshot(window, cx)
12991                    .crease_for_buffer_row(MultiBufferRow(start_row))
12992                {
12993                    Some(crease) => {
12994                        let nested_start_row = crease.range().start.row + 1;
12995                        let nested_end_row = crease.range().end.row;
12996
12997                        if current_level < fold_at_level {
12998                            stack.push((nested_start_row, nested_end_row, current_level + 1));
12999                        } else if current_level == fold_at_level {
13000                            to_fold.push(crease);
13001                        }
13002
13003                        start_row = nested_end_row + 1;
13004                    }
13005                    None => start_row += 1,
13006                }
13007            }
13008        }
13009
13010        self.fold_creases(to_fold, true, window, cx);
13011    }
13012
13013    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
13014        if self.buffer.read(cx).is_singleton() {
13015            let mut fold_ranges = Vec::new();
13016            let snapshot = self.buffer.read(cx).snapshot(cx);
13017
13018            for row in 0..snapshot.max_row().0 {
13019                if let Some(foldable_range) = self
13020                    .snapshot(window, cx)
13021                    .crease_for_buffer_row(MultiBufferRow(row))
13022                {
13023                    fold_ranges.push(foldable_range);
13024                }
13025            }
13026
13027            self.fold_creases(fold_ranges, true, window, cx);
13028        } else {
13029            self.toggle_fold_multiple_buffers = cx.spawn_in(window, |editor, mut cx| async move {
13030                editor
13031                    .update_in(&mut cx, |editor, _, cx| {
13032                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
13033                            editor.fold_buffer(buffer_id, cx);
13034                        }
13035                    })
13036                    .ok();
13037            });
13038        }
13039    }
13040
13041    pub fn fold_function_bodies(
13042        &mut self,
13043        _: &actions::FoldFunctionBodies,
13044        window: &mut Window,
13045        cx: &mut Context<Self>,
13046    ) {
13047        let snapshot = self.buffer.read(cx).snapshot(cx);
13048
13049        let ranges = snapshot
13050            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
13051            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
13052            .collect::<Vec<_>>();
13053
13054        let creases = ranges
13055            .into_iter()
13056            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
13057            .collect();
13058
13059        self.fold_creases(creases, true, window, cx);
13060    }
13061
13062    pub fn fold_recursive(
13063        &mut self,
13064        _: &actions::FoldRecursive,
13065        window: &mut Window,
13066        cx: &mut Context<Self>,
13067    ) {
13068        let mut to_fold = Vec::new();
13069        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13070        let selections = self.selections.all_adjusted(cx);
13071
13072        for selection in selections {
13073            let range = selection.range().sorted();
13074            let buffer_start_row = range.start.row;
13075
13076            if range.start.row != range.end.row {
13077                let mut found = false;
13078                for row in range.start.row..=range.end.row {
13079                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
13080                        found = true;
13081                        to_fold.push(crease);
13082                    }
13083                }
13084                if found {
13085                    continue;
13086                }
13087            }
13088
13089            for row in (0..=range.start.row).rev() {
13090                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
13091                    if crease.range().end.row >= buffer_start_row {
13092                        to_fold.push(crease);
13093                    } else {
13094                        break;
13095                    }
13096                }
13097            }
13098        }
13099
13100        self.fold_creases(to_fold, true, window, cx);
13101    }
13102
13103    pub fn fold_at(&mut self, fold_at: &FoldAt, window: &mut Window, cx: &mut Context<Self>) {
13104        let buffer_row = fold_at.buffer_row;
13105        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13106
13107        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
13108            let autoscroll = self
13109                .selections
13110                .all::<Point>(cx)
13111                .iter()
13112                .any(|selection| crease.range().overlaps(&selection.range()));
13113
13114            self.fold_creases(vec![crease], autoscroll, window, cx);
13115        }
13116    }
13117
13118    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
13119        if self.is_singleton(cx) {
13120            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13121            let buffer = &display_map.buffer_snapshot;
13122            let selections = self.selections.all::<Point>(cx);
13123            let ranges = selections
13124                .iter()
13125                .map(|s| {
13126                    let range = s.display_range(&display_map).sorted();
13127                    let mut start = range.start.to_point(&display_map);
13128                    let mut end = range.end.to_point(&display_map);
13129                    start.column = 0;
13130                    end.column = buffer.line_len(MultiBufferRow(end.row));
13131                    start..end
13132                })
13133                .collect::<Vec<_>>();
13134
13135            self.unfold_ranges(&ranges, true, true, cx);
13136        } else {
13137            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
13138            let buffer_ids: HashSet<_> = multi_buffer_snapshot
13139                .ranges_to_buffer_ranges(self.selections.disjoint_anchor_ranges())
13140                .map(|(snapshot, _, _)| snapshot.remote_id())
13141                .collect();
13142            for buffer_id in buffer_ids {
13143                self.unfold_buffer(buffer_id, cx);
13144            }
13145        }
13146    }
13147
13148    pub fn unfold_recursive(
13149        &mut self,
13150        _: &UnfoldRecursive,
13151        _window: &mut Window,
13152        cx: &mut Context<Self>,
13153    ) {
13154        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13155        let selections = self.selections.all::<Point>(cx);
13156        let ranges = selections
13157            .iter()
13158            .map(|s| {
13159                let mut range = s.display_range(&display_map).sorted();
13160                *range.start.column_mut() = 0;
13161                *range.end.column_mut() = display_map.line_len(range.end.row());
13162                let start = range.start.to_point(&display_map);
13163                let end = range.end.to_point(&display_map);
13164                start..end
13165            })
13166            .collect::<Vec<_>>();
13167
13168        self.unfold_ranges(&ranges, true, true, cx);
13169    }
13170
13171    pub fn unfold_at(
13172        &mut self,
13173        unfold_at: &UnfoldAt,
13174        _window: &mut Window,
13175        cx: &mut Context<Self>,
13176    ) {
13177        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13178
13179        let intersection_range = Point::new(unfold_at.buffer_row.0, 0)
13180            ..Point::new(
13181                unfold_at.buffer_row.0,
13182                display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
13183            );
13184
13185        let autoscroll = self
13186            .selections
13187            .all::<Point>(cx)
13188            .iter()
13189            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
13190
13191        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
13192    }
13193
13194    pub fn unfold_all(
13195        &mut self,
13196        _: &actions::UnfoldAll,
13197        _window: &mut Window,
13198        cx: &mut Context<Self>,
13199    ) {
13200        if self.buffer.read(cx).is_singleton() {
13201            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13202            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
13203        } else {
13204            self.toggle_fold_multiple_buffers = cx.spawn(|editor, mut cx| async move {
13205                editor
13206                    .update(&mut cx, |editor, cx| {
13207                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
13208                            editor.unfold_buffer(buffer_id, cx);
13209                        }
13210                    })
13211                    .ok();
13212            });
13213        }
13214    }
13215
13216    pub fn fold_selected_ranges(
13217        &mut self,
13218        _: &FoldSelectedRanges,
13219        window: &mut Window,
13220        cx: &mut Context<Self>,
13221    ) {
13222        let selections = self.selections.all::<Point>(cx);
13223        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13224        let line_mode = self.selections.line_mode;
13225        let ranges = selections
13226            .into_iter()
13227            .map(|s| {
13228                if line_mode {
13229                    let start = Point::new(s.start.row, 0);
13230                    let end = Point::new(
13231                        s.end.row,
13232                        display_map
13233                            .buffer_snapshot
13234                            .line_len(MultiBufferRow(s.end.row)),
13235                    );
13236                    Crease::simple(start..end, display_map.fold_placeholder.clone())
13237                } else {
13238                    Crease::simple(s.start..s.end, display_map.fold_placeholder.clone())
13239                }
13240            })
13241            .collect::<Vec<_>>();
13242        self.fold_creases(ranges, true, window, cx);
13243    }
13244
13245    pub fn fold_ranges<T: ToOffset + Clone>(
13246        &mut self,
13247        ranges: Vec<Range<T>>,
13248        auto_scroll: bool,
13249        window: &mut Window,
13250        cx: &mut Context<Self>,
13251    ) {
13252        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13253        let ranges = ranges
13254            .into_iter()
13255            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
13256            .collect::<Vec<_>>();
13257        self.fold_creases(ranges, auto_scroll, window, cx);
13258    }
13259
13260    pub fn fold_creases<T: ToOffset + Clone>(
13261        &mut self,
13262        creases: Vec<Crease<T>>,
13263        auto_scroll: bool,
13264        window: &mut Window,
13265        cx: &mut Context<Self>,
13266    ) {
13267        if creases.is_empty() {
13268            return;
13269        }
13270
13271        let mut buffers_affected = HashSet::default();
13272        let multi_buffer = self.buffer().read(cx);
13273        for crease in &creases {
13274            if let Some((_, buffer, _)) =
13275                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
13276            {
13277                buffers_affected.insert(buffer.read(cx).remote_id());
13278            };
13279        }
13280
13281        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
13282
13283        if auto_scroll {
13284            self.request_autoscroll(Autoscroll::fit(), cx);
13285        }
13286
13287        cx.notify();
13288
13289        if let Some(active_diagnostics) = self.active_diagnostics.take() {
13290            // Clear diagnostics block when folding a range that contains it.
13291            let snapshot = self.snapshot(window, cx);
13292            if snapshot.intersects_fold(active_diagnostics.primary_range.start) {
13293                drop(snapshot);
13294                self.active_diagnostics = Some(active_diagnostics);
13295                self.dismiss_diagnostics(cx);
13296            } else {
13297                self.active_diagnostics = Some(active_diagnostics);
13298            }
13299        }
13300
13301        self.scrollbar_marker_state.dirty = true;
13302    }
13303
13304    /// Removes any folds whose ranges intersect any of the given ranges.
13305    pub fn unfold_ranges<T: ToOffset + Clone>(
13306        &mut self,
13307        ranges: &[Range<T>],
13308        inclusive: bool,
13309        auto_scroll: bool,
13310        cx: &mut Context<Self>,
13311    ) {
13312        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
13313            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
13314        });
13315    }
13316
13317    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
13318        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
13319            return;
13320        }
13321        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
13322        self.display_map.update(cx, |display_map, cx| {
13323            display_map.fold_buffers([buffer_id], cx)
13324        });
13325        cx.emit(EditorEvent::BufferFoldToggled {
13326            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
13327            folded: true,
13328        });
13329        cx.notify();
13330    }
13331
13332    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
13333        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
13334            return;
13335        }
13336        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
13337        self.display_map.update(cx, |display_map, cx| {
13338            display_map.unfold_buffers([buffer_id], cx);
13339        });
13340        cx.emit(EditorEvent::BufferFoldToggled {
13341            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
13342            folded: false,
13343        });
13344        cx.notify();
13345    }
13346
13347    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
13348        self.display_map.read(cx).is_buffer_folded(buffer)
13349    }
13350
13351    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
13352        self.display_map.read(cx).folded_buffers()
13353    }
13354
13355    /// Removes any folds with the given ranges.
13356    pub fn remove_folds_with_type<T: ToOffset + Clone>(
13357        &mut self,
13358        ranges: &[Range<T>],
13359        type_id: TypeId,
13360        auto_scroll: bool,
13361        cx: &mut Context<Self>,
13362    ) {
13363        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
13364            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
13365        });
13366    }
13367
13368    fn remove_folds_with<T: ToOffset + Clone>(
13369        &mut self,
13370        ranges: &[Range<T>],
13371        auto_scroll: bool,
13372        cx: &mut Context<Self>,
13373        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
13374    ) {
13375        if ranges.is_empty() {
13376            return;
13377        }
13378
13379        let mut buffers_affected = HashSet::default();
13380        let multi_buffer = self.buffer().read(cx);
13381        for range in ranges {
13382            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
13383                buffers_affected.insert(buffer.read(cx).remote_id());
13384            };
13385        }
13386
13387        self.display_map.update(cx, update);
13388
13389        if auto_scroll {
13390            self.request_autoscroll(Autoscroll::fit(), cx);
13391        }
13392
13393        cx.notify();
13394        self.scrollbar_marker_state.dirty = true;
13395        self.active_indent_guides_state.dirty = true;
13396    }
13397
13398    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
13399        self.display_map.read(cx).fold_placeholder.clone()
13400    }
13401
13402    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
13403        self.buffer.update(cx, |buffer, cx| {
13404            buffer.set_all_diff_hunks_expanded(cx);
13405        });
13406    }
13407
13408    pub fn expand_all_diff_hunks(
13409        &mut self,
13410        _: &ExpandAllDiffHunks,
13411        _window: &mut Window,
13412        cx: &mut Context<Self>,
13413    ) {
13414        self.buffer.update(cx, |buffer, cx| {
13415            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
13416        });
13417    }
13418
13419    pub fn toggle_selected_diff_hunks(
13420        &mut self,
13421        _: &ToggleSelectedDiffHunks,
13422        _window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) {
13425        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
13426        self.toggle_diff_hunks_in_ranges(ranges, cx);
13427    }
13428
13429    pub fn diff_hunks_in_ranges<'a>(
13430        &'a self,
13431        ranges: &'a [Range<Anchor>],
13432        buffer: &'a MultiBufferSnapshot,
13433    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
13434        ranges.iter().flat_map(move |range| {
13435            let end_excerpt_id = range.end.excerpt_id;
13436            let range = range.to_point(buffer);
13437            let mut peek_end = range.end;
13438            if range.end.row < buffer.max_row().0 {
13439                peek_end = Point::new(range.end.row + 1, 0);
13440            }
13441            buffer
13442                .diff_hunks_in_range(range.start..peek_end)
13443                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
13444        })
13445    }
13446
13447    pub fn has_stageable_diff_hunks_in_ranges(
13448        &self,
13449        ranges: &[Range<Anchor>],
13450        snapshot: &MultiBufferSnapshot,
13451    ) -> bool {
13452        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
13453        hunks.any(|hunk| hunk.secondary_status != DiffHunkSecondaryStatus::None)
13454    }
13455
13456    pub fn toggle_staged_selected_diff_hunks(
13457        &mut self,
13458        _: &::git::ToggleStaged,
13459        window: &mut Window,
13460        cx: &mut Context<Self>,
13461    ) {
13462        let snapshot = self.buffer.read(cx).snapshot(cx);
13463        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
13464        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
13465        self.stage_or_unstage_diff_hunks(stage, &ranges, window, cx);
13466    }
13467
13468    pub fn stage_and_next(
13469        &mut self,
13470        _: &::git::StageAndNext,
13471        window: &mut Window,
13472        cx: &mut Context<Self>,
13473    ) {
13474        self.do_stage_or_unstage_and_next(true, window, cx);
13475    }
13476
13477    pub fn unstage_and_next(
13478        &mut self,
13479        _: &::git::UnstageAndNext,
13480        window: &mut Window,
13481        cx: &mut Context<Self>,
13482    ) {
13483        self.do_stage_or_unstage_and_next(false, window, cx);
13484    }
13485
13486    pub fn stage_or_unstage_diff_hunks(
13487        &mut self,
13488        stage: bool,
13489        ranges: &[Range<Anchor>],
13490        window: &mut Window,
13491        cx: &mut Context<Self>,
13492    ) {
13493        let snapshot = self.buffer.read(cx).snapshot(cx);
13494        let Some(project) = &self.project else {
13495            return;
13496        };
13497
13498        let chunk_by = self
13499            .diff_hunks_in_ranges(&ranges, &snapshot)
13500            .chunk_by(|hunk| hunk.buffer_id);
13501        for (buffer_id, hunks) in &chunk_by {
13502            Self::do_stage_or_unstage(project, stage, buffer_id, hunks, &snapshot, window, cx);
13503        }
13504    }
13505
13506    fn do_stage_or_unstage_and_next(
13507        &mut self,
13508        stage: bool,
13509        window: &mut Window,
13510        cx: &mut Context<Self>,
13511    ) {
13512        let mut ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
13513        if ranges.iter().any(|range| range.start != range.end) {
13514            self.stage_or_unstage_diff_hunks(stage, &ranges[..], window, cx);
13515            return;
13516        }
13517
13518        if !self.buffer().read(cx).is_singleton() {
13519            if let Some((excerpt_id, buffer, range)) = self.active_excerpt(cx) {
13520                if buffer.read(cx).is_empty() {
13521                    let buffer = buffer.read(cx);
13522                    let Some(file) = buffer.file() else {
13523                        return;
13524                    };
13525                    let project_path = project::ProjectPath {
13526                        worktree_id: file.worktree_id(cx),
13527                        path: file.path().clone(),
13528                    };
13529                    let Some(project) = self.project.as_ref() else {
13530                        return;
13531                    };
13532                    let project = project.read(cx);
13533
13534                    let Some(repo) = project.git_store().read(cx).active_repository() else {
13535                        return;
13536                    };
13537
13538                    repo.update(cx, |repo, cx| {
13539                        let Some(repo_path) = repo.project_path_to_repo_path(&project_path) else {
13540                            return;
13541                        };
13542                        let Some(status) = repo.repository_entry.status_for_path(&repo_path) else {
13543                            return;
13544                        };
13545                        if stage && status.status == FileStatus::Untracked {
13546                            repo.stage_entries(vec![repo_path], cx)
13547                                .detach_and_log_err(cx);
13548                            return;
13549                        }
13550                    })
13551                }
13552                ranges = vec![multi_buffer::Anchor::range_in_buffer(
13553                    excerpt_id,
13554                    buffer.read(cx).remote_id(),
13555                    range,
13556                )];
13557                self.stage_or_unstage_diff_hunks(stage, &ranges[..], window, cx);
13558                let snapshot = self.buffer().read(cx).snapshot(cx);
13559                let mut point = ranges.last().unwrap().end.to_point(&snapshot);
13560                if point.row < snapshot.max_row().0 {
13561                    point.row += 1;
13562                    point.column = 0;
13563                    point = snapshot.clip_point(point, Bias::Right);
13564                    self.change_selections(Some(Autoscroll::top_relative(6)), window, cx, |s| {
13565                        s.select_ranges([point..point]);
13566                    })
13567                }
13568                return;
13569            }
13570        }
13571        self.stage_or_unstage_diff_hunks(stage, &ranges[..], window, cx);
13572        self.go_to_next_hunk(&Default::default(), window, cx);
13573    }
13574
13575    fn do_stage_or_unstage(
13576        project: &Entity<Project>,
13577        stage: bool,
13578        buffer_id: BufferId,
13579        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
13580        snapshot: &MultiBufferSnapshot,
13581        window: &mut Window,
13582        cx: &mut App,
13583    ) {
13584        let Some(buffer) = project.read(cx).buffer_for_id(buffer_id, cx) else {
13585            log::debug!("no buffer for id");
13586            return;
13587        };
13588        let buffer_snapshot = buffer.read(cx).snapshot();
13589        let file_exists = buffer_snapshot
13590            .file()
13591            .is_some_and(|file| file.disk_state().exists());
13592        let Some((repo, path)) = project
13593            .read(cx)
13594            .repository_and_path_for_buffer_id(buffer_id, cx)
13595        else {
13596            log::debug!("no git repo for buffer id");
13597            return;
13598        };
13599        let Some(diff) = snapshot.diff_for_buffer_id(buffer_id) else {
13600            log::debug!("no diff for buffer id");
13601            return;
13602        };
13603
13604        let new_index_text = if !stage && diff.is_single_insertion || stage && !file_exists {
13605            log::debug!("removing from index");
13606            None
13607        } else {
13608            diff.new_secondary_text_for_stage_or_unstage(
13609                stage,
13610                hunks.filter_map(|hunk| {
13611                    if stage && hunk.secondary_status == DiffHunkSecondaryStatus::None {
13612                        return None;
13613                    } else if !stage
13614                        && hunk.secondary_status == DiffHunkSecondaryStatus::HasSecondaryHunk
13615                    {
13616                        return None;
13617                    }
13618                    Some((hunk.buffer_range.clone(), hunk.diff_base_byte_range.clone()))
13619                }),
13620                &buffer_snapshot,
13621                cx,
13622            )
13623        };
13624        if file_exists {
13625            let buffer_store = project.read(cx).buffer_store().clone();
13626            buffer_store
13627                .update(cx, |buffer_store, cx| buffer_store.save_buffer(buffer, cx))
13628                .detach_and_log_err(cx);
13629        }
13630        let recv = repo
13631            .read(cx)
13632            .set_index_text(&path, new_index_text.map(|rope| rope.to_string()));
13633
13634        cx.background_spawn(async move { recv.await? })
13635            .detach_and_notify_err(window, cx);
13636    }
13637
13638    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
13639        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
13640        self.buffer
13641            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
13642    }
13643
13644    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
13645        self.buffer.update(cx, |buffer, cx| {
13646            let ranges = vec![Anchor::min()..Anchor::max()];
13647            if !buffer.all_diff_hunks_expanded()
13648                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
13649            {
13650                buffer.collapse_diff_hunks(ranges, cx);
13651                true
13652            } else {
13653                false
13654            }
13655        })
13656    }
13657
13658    fn toggle_diff_hunks_in_ranges(
13659        &mut self,
13660        ranges: Vec<Range<Anchor>>,
13661        cx: &mut Context<'_, Editor>,
13662    ) {
13663        self.buffer.update(cx, |buffer, cx| {
13664            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
13665            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
13666        })
13667    }
13668
13669    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
13670        self.buffer.update(cx, |buffer, cx| {
13671            let snapshot = buffer.snapshot(cx);
13672            let excerpt_id = range.end.excerpt_id;
13673            let point_range = range.to_point(&snapshot);
13674            let expand = !buffer.single_hunk_is_expanded(range, cx);
13675            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
13676        })
13677    }
13678
13679    pub(crate) fn apply_all_diff_hunks(
13680        &mut self,
13681        _: &ApplyAllDiffHunks,
13682        window: &mut Window,
13683        cx: &mut Context<Self>,
13684    ) {
13685        let buffers = self.buffer.read(cx).all_buffers();
13686        for branch_buffer in buffers {
13687            branch_buffer.update(cx, |branch_buffer, cx| {
13688                branch_buffer.merge_into_base(Vec::new(), cx);
13689            });
13690        }
13691
13692        if let Some(project) = self.project.clone() {
13693            self.save(true, project, window, cx).detach_and_log_err(cx);
13694        }
13695    }
13696
13697    pub(crate) fn apply_selected_diff_hunks(
13698        &mut self,
13699        _: &ApplyDiffHunk,
13700        window: &mut Window,
13701        cx: &mut Context<Self>,
13702    ) {
13703        let snapshot = self.snapshot(window, cx);
13704        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx).into_iter());
13705        let mut ranges_by_buffer = HashMap::default();
13706        self.transact(window, cx, |editor, _window, cx| {
13707            for hunk in hunks {
13708                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
13709                    ranges_by_buffer
13710                        .entry(buffer.clone())
13711                        .or_insert_with(Vec::new)
13712                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
13713                }
13714            }
13715
13716            for (buffer, ranges) in ranges_by_buffer {
13717                buffer.update(cx, |buffer, cx| {
13718                    buffer.merge_into_base(ranges, cx);
13719                });
13720            }
13721        });
13722
13723        if let Some(project) = self.project.clone() {
13724            self.save(true, project, window, cx).detach_and_log_err(cx);
13725        }
13726    }
13727
13728    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
13729        if hovered != self.gutter_hovered {
13730            self.gutter_hovered = hovered;
13731            cx.notify();
13732        }
13733    }
13734
13735    pub fn insert_blocks(
13736        &mut self,
13737        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
13738        autoscroll: Option<Autoscroll>,
13739        cx: &mut Context<Self>,
13740    ) -> Vec<CustomBlockId> {
13741        let blocks = self
13742            .display_map
13743            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
13744        if let Some(autoscroll) = autoscroll {
13745            self.request_autoscroll(autoscroll, cx);
13746        }
13747        cx.notify();
13748        blocks
13749    }
13750
13751    pub fn resize_blocks(
13752        &mut self,
13753        heights: HashMap<CustomBlockId, u32>,
13754        autoscroll: Option<Autoscroll>,
13755        cx: &mut Context<Self>,
13756    ) {
13757        self.display_map
13758            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
13759        if let Some(autoscroll) = autoscroll {
13760            self.request_autoscroll(autoscroll, cx);
13761        }
13762        cx.notify();
13763    }
13764
13765    pub fn replace_blocks(
13766        &mut self,
13767        renderers: HashMap<CustomBlockId, RenderBlock>,
13768        autoscroll: Option<Autoscroll>,
13769        cx: &mut Context<Self>,
13770    ) {
13771        self.display_map
13772            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
13773        if let Some(autoscroll) = autoscroll {
13774            self.request_autoscroll(autoscroll, cx);
13775        }
13776        cx.notify();
13777    }
13778
13779    pub fn remove_blocks(
13780        &mut self,
13781        block_ids: HashSet<CustomBlockId>,
13782        autoscroll: Option<Autoscroll>,
13783        cx: &mut Context<Self>,
13784    ) {
13785        self.display_map.update(cx, |display_map, cx| {
13786            display_map.remove_blocks(block_ids, cx)
13787        });
13788        if let Some(autoscroll) = autoscroll {
13789            self.request_autoscroll(autoscroll, cx);
13790        }
13791        cx.notify();
13792    }
13793
13794    pub fn row_for_block(
13795        &self,
13796        block_id: CustomBlockId,
13797        cx: &mut Context<Self>,
13798    ) -> Option<DisplayRow> {
13799        self.display_map
13800            .update(cx, |map, cx| map.row_for_block(block_id, cx))
13801    }
13802
13803    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
13804        self.focused_block = Some(focused_block);
13805    }
13806
13807    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
13808        self.focused_block.take()
13809    }
13810
13811    pub fn insert_creases(
13812        &mut self,
13813        creases: impl IntoIterator<Item = Crease<Anchor>>,
13814        cx: &mut Context<Self>,
13815    ) -> Vec<CreaseId> {
13816        self.display_map
13817            .update(cx, |map, cx| map.insert_creases(creases, cx))
13818    }
13819
13820    pub fn remove_creases(
13821        &mut self,
13822        ids: impl IntoIterator<Item = CreaseId>,
13823        cx: &mut Context<Self>,
13824    ) {
13825        self.display_map
13826            .update(cx, |map, cx| map.remove_creases(ids, cx));
13827    }
13828
13829    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
13830        self.display_map
13831            .update(cx, |map, cx| map.snapshot(cx))
13832            .longest_row()
13833    }
13834
13835    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
13836        self.display_map
13837            .update(cx, |map, cx| map.snapshot(cx))
13838            .max_point()
13839    }
13840
13841    pub fn text(&self, cx: &App) -> String {
13842        self.buffer.read(cx).read(cx).text()
13843    }
13844
13845    pub fn is_empty(&self, cx: &App) -> bool {
13846        self.buffer.read(cx).read(cx).is_empty()
13847    }
13848
13849    pub fn text_option(&self, cx: &App) -> Option<String> {
13850        let text = self.text(cx);
13851        let text = text.trim();
13852
13853        if text.is_empty() {
13854            return None;
13855        }
13856
13857        Some(text.to_string())
13858    }
13859
13860    pub fn set_text(
13861        &mut self,
13862        text: impl Into<Arc<str>>,
13863        window: &mut Window,
13864        cx: &mut Context<Self>,
13865    ) {
13866        self.transact(window, cx, |this, _, cx| {
13867            this.buffer
13868                .read(cx)
13869                .as_singleton()
13870                .expect("you can only call set_text on editors for singleton buffers")
13871                .update(cx, |buffer, cx| buffer.set_text(text, cx));
13872        });
13873    }
13874
13875    pub fn display_text(&self, cx: &mut App) -> String {
13876        self.display_map
13877            .update(cx, |map, cx| map.snapshot(cx))
13878            .text()
13879    }
13880
13881    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
13882        let mut wrap_guides = smallvec::smallvec![];
13883
13884        if self.show_wrap_guides == Some(false) {
13885            return wrap_guides;
13886        }
13887
13888        let settings = self.buffer.read(cx).settings_at(0, cx);
13889        if settings.show_wrap_guides {
13890            if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
13891                wrap_guides.push((soft_wrap as usize, true));
13892            } else if let SoftWrap::Bounded(soft_wrap) = self.soft_wrap_mode(cx) {
13893                wrap_guides.push((soft_wrap as usize, true));
13894            }
13895            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
13896        }
13897
13898        wrap_guides
13899    }
13900
13901    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
13902        let settings = self.buffer.read(cx).settings_at(0, cx);
13903        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
13904        match mode {
13905            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
13906                SoftWrap::None
13907            }
13908            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
13909            language_settings::SoftWrap::PreferredLineLength => {
13910                SoftWrap::Column(settings.preferred_line_length)
13911            }
13912            language_settings::SoftWrap::Bounded => {
13913                SoftWrap::Bounded(settings.preferred_line_length)
13914            }
13915        }
13916    }
13917
13918    pub fn set_soft_wrap_mode(
13919        &mut self,
13920        mode: language_settings::SoftWrap,
13921
13922        cx: &mut Context<Self>,
13923    ) {
13924        self.soft_wrap_mode_override = Some(mode);
13925        cx.notify();
13926    }
13927
13928    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
13929        self.text_style_refinement = Some(style);
13930    }
13931
13932    /// called by the Element so we know what style we were most recently rendered with.
13933    pub(crate) fn set_style(
13934        &mut self,
13935        style: EditorStyle,
13936        window: &mut Window,
13937        cx: &mut Context<Self>,
13938    ) {
13939        let rem_size = window.rem_size();
13940        self.display_map.update(cx, |map, cx| {
13941            map.set_font(
13942                style.text.font(),
13943                style.text.font_size.to_pixels(rem_size),
13944                cx,
13945            )
13946        });
13947        self.style = Some(style);
13948    }
13949
13950    pub fn style(&self) -> Option<&EditorStyle> {
13951        self.style.as_ref()
13952    }
13953
13954    // Called by the element. This method is not designed to be called outside of the editor
13955    // element's layout code because it does not notify when rewrapping is computed synchronously.
13956    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
13957        self.display_map
13958            .update(cx, |map, cx| map.set_wrap_width(width, cx))
13959    }
13960
13961    pub fn set_soft_wrap(&mut self) {
13962        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
13963    }
13964
13965    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
13966        if self.soft_wrap_mode_override.is_some() {
13967            self.soft_wrap_mode_override.take();
13968        } else {
13969            let soft_wrap = match self.soft_wrap_mode(cx) {
13970                SoftWrap::GitDiff => return,
13971                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
13972                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
13973                    language_settings::SoftWrap::None
13974                }
13975            };
13976            self.soft_wrap_mode_override = Some(soft_wrap);
13977        }
13978        cx.notify();
13979    }
13980
13981    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
13982        let Some(workspace) = self.workspace() else {
13983            return;
13984        };
13985        let fs = workspace.read(cx).app_state().fs.clone();
13986        let current_show = TabBarSettings::get_global(cx).show;
13987        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
13988            setting.show = Some(!current_show);
13989        });
13990    }
13991
13992    pub fn toggle_indent_guides(
13993        &mut self,
13994        _: &ToggleIndentGuides,
13995        _: &mut Window,
13996        cx: &mut Context<Self>,
13997    ) {
13998        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
13999            self.buffer
14000                .read(cx)
14001                .settings_at(0, cx)
14002                .indent_guides
14003                .enabled
14004        });
14005        self.show_indent_guides = Some(!currently_enabled);
14006        cx.notify();
14007    }
14008
14009    fn should_show_indent_guides(&self) -> Option<bool> {
14010        self.show_indent_guides
14011    }
14012
14013    pub fn toggle_line_numbers(
14014        &mut self,
14015        _: &ToggleLineNumbers,
14016        _: &mut Window,
14017        cx: &mut Context<Self>,
14018    ) {
14019        let mut editor_settings = EditorSettings::get_global(cx).clone();
14020        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
14021        EditorSettings::override_global(editor_settings, cx);
14022    }
14023
14024    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
14025        self.use_relative_line_numbers
14026            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
14027    }
14028
14029    pub fn toggle_relative_line_numbers(
14030        &mut self,
14031        _: &ToggleRelativeLineNumbers,
14032        _: &mut Window,
14033        cx: &mut Context<Self>,
14034    ) {
14035        let is_relative = self.should_use_relative_line_numbers(cx);
14036        self.set_relative_line_number(Some(!is_relative), cx)
14037    }
14038
14039    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
14040        self.use_relative_line_numbers = is_relative;
14041        cx.notify();
14042    }
14043
14044    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
14045        self.show_gutter = show_gutter;
14046        cx.notify();
14047    }
14048
14049    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
14050        self.show_scrollbars = show_scrollbars;
14051        cx.notify();
14052    }
14053
14054    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
14055        self.show_line_numbers = Some(show_line_numbers);
14056        cx.notify();
14057    }
14058
14059    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
14060        self.show_git_diff_gutter = Some(show_git_diff_gutter);
14061        cx.notify();
14062    }
14063
14064    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
14065        self.show_code_actions = Some(show_code_actions);
14066        cx.notify();
14067    }
14068
14069    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
14070        self.show_runnables = Some(show_runnables);
14071        cx.notify();
14072    }
14073
14074    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
14075        if self.display_map.read(cx).masked != masked {
14076            self.display_map.update(cx, |map, _| map.masked = masked);
14077        }
14078        cx.notify()
14079    }
14080
14081    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
14082        self.show_wrap_guides = Some(show_wrap_guides);
14083        cx.notify();
14084    }
14085
14086    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
14087        self.show_indent_guides = Some(show_indent_guides);
14088        cx.notify();
14089    }
14090
14091    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
14092        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
14093            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
14094                if let Some(dir) = file.abs_path(cx).parent() {
14095                    return Some(dir.to_owned());
14096                }
14097            }
14098
14099            if let Some(project_path) = buffer.read(cx).project_path(cx) {
14100                return Some(project_path.path.to_path_buf());
14101            }
14102        }
14103
14104        None
14105    }
14106
14107    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
14108        self.active_excerpt(cx)?
14109            .1
14110            .read(cx)
14111            .file()
14112            .and_then(|f| f.as_local())
14113    }
14114
14115    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
14116        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
14117            let buffer = buffer.read(cx);
14118            if let Some(project_path) = buffer.project_path(cx) {
14119                let project = self.project.as_ref()?.read(cx);
14120                project.absolute_path(&project_path, cx)
14121            } else {
14122                buffer
14123                    .file()
14124                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
14125            }
14126        })
14127    }
14128
14129    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
14130        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
14131            let project_path = buffer.read(cx).project_path(cx)?;
14132            let project = self.project.as_ref()?.read(cx);
14133            let entry = project.entry_for_path(&project_path, cx)?;
14134            let path = entry.path.to_path_buf();
14135            Some(path)
14136        })
14137    }
14138
14139    pub fn reveal_in_finder(
14140        &mut self,
14141        _: &RevealInFileManager,
14142        _window: &mut Window,
14143        cx: &mut Context<Self>,
14144    ) {
14145        if let Some(target) = self.target_file(cx) {
14146            cx.reveal_path(&target.abs_path(cx));
14147        }
14148    }
14149
14150    pub fn copy_path(
14151        &mut self,
14152        _: &zed_actions::workspace::CopyPath,
14153        _window: &mut Window,
14154        cx: &mut Context<Self>,
14155    ) {
14156        if let Some(path) = self.target_file_abs_path(cx) {
14157            if let Some(path) = path.to_str() {
14158                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
14159            }
14160        }
14161    }
14162
14163    pub fn copy_relative_path(
14164        &mut self,
14165        _: &zed_actions::workspace::CopyRelativePath,
14166        _window: &mut Window,
14167        cx: &mut Context<Self>,
14168    ) {
14169        if let Some(path) = self.target_file_path(cx) {
14170            if let Some(path) = path.to_str() {
14171                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
14172            }
14173        }
14174    }
14175
14176    pub fn copy_file_name_without_extension(
14177        &mut self,
14178        _: &CopyFileNameWithoutExtension,
14179        _: &mut Window,
14180        cx: &mut Context<Self>,
14181    ) {
14182        if let Some(file) = self.target_file(cx) {
14183            if let Some(file_stem) = file.path().file_stem() {
14184                if let Some(name) = file_stem.to_str() {
14185                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
14186                }
14187            }
14188        }
14189    }
14190
14191    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
14192        if let Some(file) = self.target_file(cx) {
14193            if let Some(file_name) = file.path().file_name() {
14194                if let Some(name) = file_name.to_str() {
14195                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
14196                }
14197            }
14198        }
14199    }
14200
14201    pub fn toggle_git_blame(
14202        &mut self,
14203        _: &ToggleGitBlame,
14204        window: &mut Window,
14205        cx: &mut Context<Self>,
14206    ) {
14207        self.show_git_blame_gutter = !self.show_git_blame_gutter;
14208
14209        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
14210            self.start_git_blame(true, window, cx);
14211        }
14212
14213        cx.notify();
14214    }
14215
14216    pub fn toggle_git_blame_inline(
14217        &mut self,
14218        _: &ToggleGitBlameInline,
14219        window: &mut Window,
14220        cx: &mut Context<Self>,
14221    ) {
14222        self.toggle_git_blame_inline_internal(true, window, cx);
14223        cx.notify();
14224    }
14225
14226    pub fn git_blame_inline_enabled(&self) -> bool {
14227        self.git_blame_inline_enabled
14228    }
14229
14230    pub fn toggle_selection_menu(
14231        &mut self,
14232        _: &ToggleSelectionMenu,
14233        _: &mut Window,
14234        cx: &mut Context<Self>,
14235    ) {
14236        self.show_selection_menu = self
14237            .show_selection_menu
14238            .map(|show_selections_menu| !show_selections_menu)
14239            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
14240
14241        cx.notify();
14242    }
14243
14244    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
14245        self.show_selection_menu
14246            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
14247    }
14248
14249    fn start_git_blame(
14250        &mut self,
14251        user_triggered: bool,
14252        window: &mut Window,
14253        cx: &mut Context<Self>,
14254    ) {
14255        if let Some(project) = self.project.as_ref() {
14256            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
14257                return;
14258            };
14259
14260            if buffer.read(cx).file().is_none() {
14261                return;
14262            }
14263
14264            let focused = self.focus_handle(cx).contains_focused(window, cx);
14265
14266            let project = project.clone();
14267            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
14268            self.blame_subscription =
14269                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
14270            self.blame = Some(blame);
14271        }
14272    }
14273
14274    fn toggle_git_blame_inline_internal(
14275        &mut self,
14276        user_triggered: bool,
14277        window: &mut Window,
14278        cx: &mut Context<Self>,
14279    ) {
14280        if self.git_blame_inline_enabled {
14281            self.git_blame_inline_enabled = false;
14282            self.show_git_blame_inline = false;
14283            self.show_git_blame_inline_delay_task.take();
14284        } else {
14285            self.git_blame_inline_enabled = true;
14286            self.start_git_blame_inline(user_triggered, window, cx);
14287        }
14288
14289        cx.notify();
14290    }
14291
14292    fn start_git_blame_inline(
14293        &mut self,
14294        user_triggered: bool,
14295        window: &mut Window,
14296        cx: &mut Context<Self>,
14297    ) {
14298        self.start_git_blame(user_triggered, window, cx);
14299
14300        if ProjectSettings::get_global(cx)
14301            .git
14302            .inline_blame_delay()
14303            .is_some()
14304        {
14305            self.start_inline_blame_timer(window, cx);
14306        } else {
14307            self.show_git_blame_inline = true
14308        }
14309    }
14310
14311    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
14312        self.blame.as_ref()
14313    }
14314
14315    pub fn show_git_blame_gutter(&self) -> bool {
14316        self.show_git_blame_gutter
14317    }
14318
14319    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
14320        self.show_git_blame_gutter && self.has_blame_entries(cx)
14321    }
14322
14323    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
14324        self.show_git_blame_inline
14325            && (self.focus_handle.is_focused(window)
14326                || self
14327                    .git_blame_inline_tooltip
14328                    .as_ref()
14329                    .and_then(|t| t.upgrade())
14330                    .is_some())
14331            && !self.newest_selection_head_on_empty_line(cx)
14332            && self.has_blame_entries(cx)
14333    }
14334
14335    fn has_blame_entries(&self, cx: &App) -> bool {
14336        self.blame()
14337            .map_or(false, |blame| blame.read(cx).has_generated_entries())
14338    }
14339
14340    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
14341        let cursor_anchor = self.selections.newest_anchor().head();
14342
14343        let snapshot = self.buffer.read(cx).snapshot(cx);
14344        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
14345
14346        snapshot.line_len(buffer_row) == 0
14347    }
14348
14349    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
14350        let buffer_and_selection = maybe!({
14351            let selection = self.selections.newest::<Point>(cx);
14352            let selection_range = selection.range();
14353
14354            let multi_buffer = self.buffer().read(cx);
14355            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14356            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
14357
14358            let (buffer, range, _) = if selection.reversed {
14359                buffer_ranges.first()
14360            } else {
14361                buffer_ranges.last()
14362            }?;
14363
14364            let selection = text::ToPoint::to_point(&range.start, &buffer).row
14365                ..text::ToPoint::to_point(&range.end, &buffer).row;
14366            Some((
14367                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
14368                selection,
14369            ))
14370        });
14371
14372        let Some((buffer, selection)) = buffer_and_selection else {
14373            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
14374        };
14375
14376        let Some(project) = self.project.as_ref() else {
14377            return Task::ready(Err(anyhow!("editor does not have project")));
14378        };
14379
14380        project.update(cx, |project, cx| {
14381            project.get_permalink_to_line(&buffer, selection, cx)
14382        })
14383    }
14384
14385    pub fn copy_permalink_to_line(
14386        &mut self,
14387        _: &CopyPermalinkToLine,
14388        window: &mut Window,
14389        cx: &mut Context<Self>,
14390    ) {
14391        let permalink_task = self.get_permalink_to_line(cx);
14392        let workspace = self.workspace();
14393
14394        cx.spawn_in(window, |_, mut cx| async move {
14395            match permalink_task.await {
14396                Ok(permalink) => {
14397                    cx.update(|_, cx| {
14398                        cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
14399                    })
14400                    .ok();
14401                }
14402                Err(err) => {
14403                    let message = format!("Failed to copy permalink: {err}");
14404
14405                    Err::<(), anyhow::Error>(err).log_err();
14406
14407                    if let Some(workspace) = workspace {
14408                        workspace
14409                            .update_in(&mut cx, |workspace, _, cx| {
14410                                struct CopyPermalinkToLine;
14411
14412                                workspace.show_toast(
14413                                    Toast::new(
14414                                        NotificationId::unique::<CopyPermalinkToLine>(),
14415                                        message,
14416                                    ),
14417                                    cx,
14418                                )
14419                            })
14420                            .ok();
14421                    }
14422                }
14423            }
14424        })
14425        .detach();
14426    }
14427
14428    pub fn copy_file_location(
14429        &mut self,
14430        _: &CopyFileLocation,
14431        _: &mut Window,
14432        cx: &mut Context<Self>,
14433    ) {
14434        let selection = self.selections.newest::<Point>(cx).start.row + 1;
14435        if let Some(file) = self.target_file(cx) {
14436            if let Some(path) = file.path().to_str() {
14437                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
14438            }
14439        }
14440    }
14441
14442    pub fn open_permalink_to_line(
14443        &mut self,
14444        _: &OpenPermalinkToLine,
14445        window: &mut Window,
14446        cx: &mut Context<Self>,
14447    ) {
14448        let permalink_task = self.get_permalink_to_line(cx);
14449        let workspace = self.workspace();
14450
14451        cx.spawn_in(window, |_, mut cx| async move {
14452            match permalink_task.await {
14453                Ok(permalink) => {
14454                    cx.update(|_, cx| {
14455                        cx.open_url(permalink.as_ref());
14456                    })
14457                    .ok();
14458                }
14459                Err(err) => {
14460                    let message = format!("Failed to open permalink: {err}");
14461
14462                    Err::<(), anyhow::Error>(err).log_err();
14463
14464                    if let Some(workspace) = workspace {
14465                        workspace
14466                            .update(&mut cx, |workspace, cx| {
14467                                struct OpenPermalinkToLine;
14468
14469                                workspace.show_toast(
14470                                    Toast::new(
14471                                        NotificationId::unique::<OpenPermalinkToLine>(),
14472                                        message,
14473                                    ),
14474                                    cx,
14475                                )
14476                            })
14477                            .ok();
14478                    }
14479                }
14480            }
14481        })
14482        .detach();
14483    }
14484
14485    pub fn insert_uuid_v4(
14486        &mut self,
14487        _: &InsertUuidV4,
14488        window: &mut Window,
14489        cx: &mut Context<Self>,
14490    ) {
14491        self.insert_uuid(UuidVersion::V4, window, cx);
14492    }
14493
14494    pub fn insert_uuid_v7(
14495        &mut self,
14496        _: &InsertUuidV7,
14497        window: &mut Window,
14498        cx: &mut Context<Self>,
14499    ) {
14500        self.insert_uuid(UuidVersion::V7, window, cx);
14501    }
14502
14503    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
14504        self.transact(window, cx, |this, window, cx| {
14505            let edits = this
14506                .selections
14507                .all::<Point>(cx)
14508                .into_iter()
14509                .map(|selection| {
14510                    let uuid = match version {
14511                        UuidVersion::V4 => uuid::Uuid::new_v4(),
14512                        UuidVersion::V7 => uuid::Uuid::now_v7(),
14513                    };
14514
14515                    (selection.range(), uuid.to_string())
14516                });
14517            this.edit(edits, cx);
14518            this.refresh_inline_completion(true, false, window, cx);
14519        });
14520    }
14521
14522    pub fn open_selections_in_multibuffer(
14523        &mut self,
14524        _: &OpenSelectionsInMultibuffer,
14525        window: &mut Window,
14526        cx: &mut Context<Self>,
14527    ) {
14528        let multibuffer = self.buffer.read(cx);
14529
14530        let Some(buffer) = multibuffer.as_singleton() else {
14531            return;
14532        };
14533
14534        let Some(workspace) = self.workspace() else {
14535            return;
14536        };
14537
14538        let locations = self
14539            .selections
14540            .disjoint_anchors()
14541            .iter()
14542            .map(|range| Location {
14543                buffer: buffer.clone(),
14544                range: range.start.text_anchor..range.end.text_anchor,
14545            })
14546            .collect::<Vec<_>>();
14547
14548        let title = multibuffer.title(cx).to_string();
14549
14550        cx.spawn_in(window, |_, mut cx| async move {
14551            workspace.update_in(&mut cx, |workspace, window, cx| {
14552                Self::open_locations_in_multibuffer(
14553                    workspace,
14554                    locations,
14555                    format!("Selections for '{title}'"),
14556                    false,
14557                    MultibufferSelectionMode::All,
14558                    window,
14559                    cx,
14560                );
14561            })
14562        })
14563        .detach();
14564    }
14565
14566    /// Adds a row highlight for the given range. If a row has multiple highlights, the
14567    /// last highlight added will be used.
14568    ///
14569    /// If the range ends at the beginning of a line, then that line will not be highlighted.
14570    pub fn highlight_rows<T: 'static>(
14571        &mut self,
14572        range: Range<Anchor>,
14573        color: Hsla,
14574        should_autoscroll: bool,
14575        cx: &mut Context<Self>,
14576    ) {
14577        let snapshot = self.buffer().read(cx).snapshot(cx);
14578        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
14579        let ix = row_highlights.binary_search_by(|highlight| {
14580            Ordering::Equal
14581                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
14582                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
14583        });
14584
14585        if let Err(mut ix) = ix {
14586            let index = post_inc(&mut self.highlight_order);
14587
14588            // If this range intersects with the preceding highlight, then merge it with
14589            // the preceding highlight. Otherwise insert a new highlight.
14590            let mut merged = false;
14591            if ix > 0 {
14592                let prev_highlight = &mut row_highlights[ix - 1];
14593                if prev_highlight
14594                    .range
14595                    .end
14596                    .cmp(&range.start, &snapshot)
14597                    .is_ge()
14598                {
14599                    ix -= 1;
14600                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
14601                        prev_highlight.range.end = range.end;
14602                    }
14603                    merged = true;
14604                    prev_highlight.index = index;
14605                    prev_highlight.color = color;
14606                    prev_highlight.should_autoscroll = should_autoscroll;
14607                }
14608            }
14609
14610            if !merged {
14611                row_highlights.insert(
14612                    ix,
14613                    RowHighlight {
14614                        range: range.clone(),
14615                        index,
14616                        color,
14617                        should_autoscroll,
14618                    },
14619                );
14620            }
14621
14622            // If any of the following highlights intersect with this one, merge them.
14623            while let Some(next_highlight) = row_highlights.get(ix + 1) {
14624                let highlight = &row_highlights[ix];
14625                if next_highlight
14626                    .range
14627                    .start
14628                    .cmp(&highlight.range.end, &snapshot)
14629                    .is_le()
14630                {
14631                    if next_highlight
14632                        .range
14633                        .end
14634                        .cmp(&highlight.range.end, &snapshot)
14635                        .is_gt()
14636                    {
14637                        row_highlights[ix].range.end = next_highlight.range.end;
14638                    }
14639                    row_highlights.remove(ix + 1);
14640                } else {
14641                    break;
14642                }
14643            }
14644        }
14645    }
14646
14647    /// Remove any highlighted row ranges of the given type that intersect the
14648    /// given ranges.
14649    pub fn remove_highlighted_rows<T: 'static>(
14650        &mut self,
14651        ranges_to_remove: Vec<Range<Anchor>>,
14652        cx: &mut Context<Self>,
14653    ) {
14654        let snapshot = self.buffer().read(cx).snapshot(cx);
14655        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
14656        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
14657        row_highlights.retain(|highlight| {
14658            while let Some(range_to_remove) = ranges_to_remove.peek() {
14659                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
14660                    Ordering::Less | Ordering::Equal => {
14661                        ranges_to_remove.next();
14662                    }
14663                    Ordering::Greater => {
14664                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
14665                            Ordering::Less | Ordering::Equal => {
14666                                return false;
14667                            }
14668                            Ordering::Greater => break,
14669                        }
14670                    }
14671                }
14672            }
14673
14674            true
14675        })
14676    }
14677
14678    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
14679    pub fn clear_row_highlights<T: 'static>(&mut self) {
14680        self.highlighted_rows.remove(&TypeId::of::<T>());
14681    }
14682
14683    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
14684    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
14685        self.highlighted_rows
14686            .get(&TypeId::of::<T>())
14687            .map_or(&[] as &[_], |vec| vec.as_slice())
14688            .iter()
14689            .map(|highlight| (highlight.range.clone(), highlight.color))
14690    }
14691
14692    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
14693    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
14694    /// Allows to ignore certain kinds of highlights.
14695    pub fn highlighted_display_rows(
14696        &self,
14697        window: &mut Window,
14698        cx: &mut App,
14699    ) -> BTreeMap<DisplayRow, Background> {
14700        let snapshot = self.snapshot(window, cx);
14701        let mut used_highlight_orders = HashMap::default();
14702        self.highlighted_rows
14703            .iter()
14704            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
14705            .fold(
14706                BTreeMap::<DisplayRow, Background>::new(),
14707                |mut unique_rows, highlight| {
14708                    let start = highlight.range.start.to_display_point(&snapshot);
14709                    let end = highlight.range.end.to_display_point(&snapshot);
14710                    let start_row = start.row().0;
14711                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
14712                        && end.column() == 0
14713                    {
14714                        end.row().0.saturating_sub(1)
14715                    } else {
14716                        end.row().0
14717                    };
14718                    for row in start_row..=end_row {
14719                        let used_index =
14720                            used_highlight_orders.entry(row).or_insert(highlight.index);
14721                        if highlight.index >= *used_index {
14722                            *used_index = highlight.index;
14723                            unique_rows.insert(DisplayRow(row), highlight.color.into());
14724                        }
14725                    }
14726                    unique_rows
14727                },
14728            )
14729    }
14730
14731    pub fn highlighted_display_row_for_autoscroll(
14732        &self,
14733        snapshot: &DisplaySnapshot,
14734    ) -> Option<DisplayRow> {
14735        self.highlighted_rows
14736            .values()
14737            .flat_map(|highlighted_rows| highlighted_rows.iter())
14738            .filter_map(|highlight| {
14739                if highlight.should_autoscroll {
14740                    Some(highlight.range.start.to_display_point(snapshot).row())
14741                } else {
14742                    None
14743                }
14744            })
14745            .min()
14746    }
14747
14748    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
14749        self.highlight_background::<SearchWithinRange>(
14750            ranges,
14751            |colors| colors.editor_document_highlight_read_background,
14752            cx,
14753        )
14754    }
14755
14756    pub fn set_breadcrumb_header(&mut self, new_header: String) {
14757        self.breadcrumb_header = Some(new_header);
14758    }
14759
14760    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
14761        self.clear_background_highlights::<SearchWithinRange>(cx);
14762    }
14763
14764    pub fn highlight_background<T: 'static>(
14765        &mut self,
14766        ranges: &[Range<Anchor>],
14767        color_fetcher: fn(&ThemeColors) -> Hsla,
14768        cx: &mut Context<Self>,
14769    ) {
14770        self.background_highlights
14771            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
14772        self.scrollbar_marker_state.dirty = true;
14773        cx.notify();
14774    }
14775
14776    pub fn clear_background_highlights<T: 'static>(
14777        &mut self,
14778        cx: &mut Context<Self>,
14779    ) -> Option<BackgroundHighlight> {
14780        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
14781        if !text_highlights.1.is_empty() {
14782            self.scrollbar_marker_state.dirty = true;
14783            cx.notify();
14784        }
14785        Some(text_highlights)
14786    }
14787
14788    pub fn highlight_gutter<T: 'static>(
14789        &mut self,
14790        ranges: &[Range<Anchor>],
14791        color_fetcher: fn(&App) -> Hsla,
14792        cx: &mut Context<Self>,
14793    ) {
14794        self.gutter_highlights
14795            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
14796        cx.notify();
14797    }
14798
14799    pub fn clear_gutter_highlights<T: 'static>(
14800        &mut self,
14801        cx: &mut Context<Self>,
14802    ) -> Option<GutterHighlight> {
14803        cx.notify();
14804        self.gutter_highlights.remove(&TypeId::of::<T>())
14805    }
14806
14807    #[cfg(feature = "test-support")]
14808    pub fn all_text_background_highlights(
14809        &self,
14810        window: &mut Window,
14811        cx: &mut Context<Self>,
14812    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
14813        let snapshot = self.snapshot(window, cx);
14814        let buffer = &snapshot.buffer_snapshot;
14815        let start = buffer.anchor_before(0);
14816        let end = buffer.anchor_after(buffer.len());
14817        let theme = cx.theme().colors();
14818        self.background_highlights_in_range(start..end, &snapshot, theme)
14819    }
14820
14821    #[cfg(feature = "test-support")]
14822    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
14823        let snapshot = self.buffer().read(cx).snapshot(cx);
14824
14825        let highlights = self
14826            .background_highlights
14827            .get(&TypeId::of::<items::BufferSearchHighlights>());
14828
14829        if let Some((_color, ranges)) = highlights {
14830            ranges
14831                .iter()
14832                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
14833                .collect_vec()
14834        } else {
14835            vec![]
14836        }
14837    }
14838
14839    fn document_highlights_for_position<'a>(
14840        &'a self,
14841        position: Anchor,
14842        buffer: &'a MultiBufferSnapshot,
14843    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
14844        let read_highlights = self
14845            .background_highlights
14846            .get(&TypeId::of::<DocumentHighlightRead>())
14847            .map(|h| &h.1);
14848        let write_highlights = self
14849            .background_highlights
14850            .get(&TypeId::of::<DocumentHighlightWrite>())
14851            .map(|h| &h.1);
14852        let left_position = position.bias_left(buffer);
14853        let right_position = position.bias_right(buffer);
14854        read_highlights
14855            .into_iter()
14856            .chain(write_highlights)
14857            .flat_map(move |ranges| {
14858                let start_ix = match ranges.binary_search_by(|probe| {
14859                    let cmp = probe.end.cmp(&left_position, buffer);
14860                    if cmp.is_ge() {
14861                        Ordering::Greater
14862                    } else {
14863                        Ordering::Less
14864                    }
14865                }) {
14866                    Ok(i) | Err(i) => i,
14867                };
14868
14869                ranges[start_ix..]
14870                    .iter()
14871                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
14872            })
14873    }
14874
14875    pub fn has_background_highlights<T: 'static>(&self) -> bool {
14876        self.background_highlights
14877            .get(&TypeId::of::<T>())
14878            .map_or(false, |(_, highlights)| !highlights.is_empty())
14879    }
14880
14881    pub fn background_highlights_in_range(
14882        &self,
14883        search_range: Range<Anchor>,
14884        display_snapshot: &DisplaySnapshot,
14885        theme: &ThemeColors,
14886    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
14887        let mut results = Vec::new();
14888        for (color_fetcher, ranges) in self.background_highlights.values() {
14889            let color = color_fetcher(theme);
14890            let start_ix = match ranges.binary_search_by(|probe| {
14891                let cmp = probe
14892                    .end
14893                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
14894                if cmp.is_gt() {
14895                    Ordering::Greater
14896                } else {
14897                    Ordering::Less
14898                }
14899            }) {
14900                Ok(i) | Err(i) => i,
14901            };
14902            for range in &ranges[start_ix..] {
14903                if range
14904                    .start
14905                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
14906                    .is_ge()
14907                {
14908                    break;
14909                }
14910
14911                let start = range.start.to_display_point(display_snapshot);
14912                let end = range.end.to_display_point(display_snapshot);
14913                results.push((start..end, color))
14914            }
14915        }
14916        results
14917    }
14918
14919    pub fn background_highlight_row_ranges<T: 'static>(
14920        &self,
14921        search_range: Range<Anchor>,
14922        display_snapshot: &DisplaySnapshot,
14923        count: usize,
14924    ) -> Vec<RangeInclusive<DisplayPoint>> {
14925        let mut results = Vec::new();
14926        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
14927            return vec![];
14928        };
14929
14930        let start_ix = match ranges.binary_search_by(|probe| {
14931            let cmp = probe
14932                .end
14933                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
14934            if cmp.is_gt() {
14935                Ordering::Greater
14936            } else {
14937                Ordering::Less
14938            }
14939        }) {
14940            Ok(i) | Err(i) => i,
14941        };
14942        let mut push_region = |start: Option<Point>, end: Option<Point>| {
14943            if let (Some(start_display), Some(end_display)) = (start, end) {
14944                results.push(
14945                    start_display.to_display_point(display_snapshot)
14946                        ..=end_display.to_display_point(display_snapshot),
14947                );
14948            }
14949        };
14950        let mut start_row: Option<Point> = None;
14951        let mut end_row: Option<Point> = None;
14952        if ranges.len() > count {
14953            return Vec::new();
14954        }
14955        for range in &ranges[start_ix..] {
14956            if range
14957                .start
14958                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
14959                .is_ge()
14960            {
14961                break;
14962            }
14963            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
14964            if let Some(current_row) = &end_row {
14965                if end.row == current_row.row {
14966                    continue;
14967                }
14968            }
14969            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
14970            if start_row.is_none() {
14971                assert_eq!(end_row, None);
14972                start_row = Some(start);
14973                end_row = Some(end);
14974                continue;
14975            }
14976            if let Some(current_end) = end_row.as_mut() {
14977                if start.row > current_end.row + 1 {
14978                    push_region(start_row, end_row);
14979                    start_row = Some(start);
14980                    end_row = Some(end);
14981                } else {
14982                    // Merge two hunks.
14983                    *current_end = end;
14984                }
14985            } else {
14986                unreachable!();
14987            }
14988        }
14989        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
14990        push_region(start_row, end_row);
14991        results
14992    }
14993
14994    pub fn gutter_highlights_in_range(
14995        &self,
14996        search_range: Range<Anchor>,
14997        display_snapshot: &DisplaySnapshot,
14998        cx: &App,
14999    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
15000        let mut results = Vec::new();
15001        for (color_fetcher, ranges) in self.gutter_highlights.values() {
15002            let color = color_fetcher(cx);
15003            let start_ix = match ranges.binary_search_by(|probe| {
15004                let cmp = probe
15005                    .end
15006                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
15007                if cmp.is_gt() {
15008                    Ordering::Greater
15009                } else {
15010                    Ordering::Less
15011                }
15012            }) {
15013                Ok(i) | Err(i) => i,
15014            };
15015            for range in &ranges[start_ix..] {
15016                if range
15017                    .start
15018                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
15019                    .is_ge()
15020                {
15021                    break;
15022                }
15023
15024                let start = range.start.to_display_point(display_snapshot);
15025                let end = range.end.to_display_point(display_snapshot);
15026                results.push((start..end, color))
15027            }
15028        }
15029        results
15030    }
15031
15032    /// Get the text ranges corresponding to the redaction query
15033    pub fn redacted_ranges(
15034        &self,
15035        search_range: Range<Anchor>,
15036        display_snapshot: &DisplaySnapshot,
15037        cx: &App,
15038    ) -> Vec<Range<DisplayPoint>> {
15039        display_snapshot
15040            .buffer_snapshot
15041            .redacted_ranges(search_range, |file| {
15042                if let Some(file) = file {
15043                    file.is_private()
15044                        && EditorSettings::get(
15045                            Some(SettingsLocation {
15046                                worktree_id: file.worktree_id(cx),
15047                                path: file.path().as_ref(),
15048                            }),
15049                            cx,
15050                        )
15051                        .redact_private_values
15052                } else {
15053                    false
15054                }
15055            })
15056            .map(|range| {
15057                range.start.to_display_point(display_snapshot)
15058                    ..range.end.to_display_point(display_snapshot)
15059            })
15060            .collect()
15061    }
15062
15063    pub fn highlight_text<T: 'static>(
15064        &mut self,
15065        ranges: Vec<Range<Anchor>>,
15066        style: HighlightStyle,
15067        cx: &mut Context<Self>,
15068    ) {
15069        self.display_map.update(cx, |map, _| {
15070            map.highlight_text(TypeId::of::<T>(), ranges, style)
15071        });
15072        cx.notify();
15073    }
15074
15075    pub(crate) fn highlight_inlays<T: 'static>(
15076        &mut self,
15077        highlights: Vec<InlayHighlight>,
15078        style: HighlightStyle,
15079        cx: &mut Context<Self>,
15080    ) {
15081        self.display_map.update(cx, |map, _| {
15082            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
15083        });
15084        cx.notify();
15085    }
15086
15087    pub fn text_highlights<'a, T: 'static>(
15088        &'a self,
15089        cx: &'a App,
15090    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
15091        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
15092    }
15093
15094    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
15095        let cleared = self
15096            .display_map
15097            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
15098        if cleared {
15099            cx.notify();
15100        }
15101    }
15102
15103    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
15104        (self.read_only(cx) || self.blink_manager.read(cx).visible())
15105            && self.focus_handle.is_focused(window)
15106    }
15107
15108    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
15109        self.show_cursor_when_unfocused = is_enabled;
15110        cx.notify();
15111    }
15112
15113    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
15114        cx.notify();
15115    }
15116
15117    fn on_buffer_event(
15118        &mut self,
15119        multibuffer: &Entity<MultiBuffer>,
15120        event: &multi_buffer::Event,
15121        window: &mut Window,
15122        cx: &mut Context<Self>,
15123    ) {
15124        match event {
15125            multi_buffer::Event::Edited {
15126                singleton_buffer_edited,
15127                edited_buffer: buffer_edited,
15128            } => {
15129                self.scrollbar_marker_state.dirty = true;
15130                self.active_indent_guides_state.dirty = true;
15131                self.refresh_active_diagnostics(cx);
15132                self.refresh_code_actions(window, cx);
15133                if self.has_active_inline_completion() {
15134                    self.update_visible_inline_completion(window, cx);
15135                }
15136                if let Some(buffer) = buffer_edited {
15137                    let buffer_id = buffer.read(cx).remote_id();
15138                    if !self.registered_buffers.contains_key(&buffer_id) {
15139                        if let Some(project) = self.project.as_ref() {
15140                            project.update(cx, |project, cx| {
15141                                self.registered_buffers.insert(
15142                                    buffer_id,
15143                                    project.register_buffer_with_language_servers(&buffer, cx),
15144                                );
15145                            })
15146                        }
15147                    }
15148                }
15149                cx.emit(EditorEvent::BufferEdited);
15150                cx.emit(SearchEvent::MatchesInvalidated);
15151                if *singleton_buffer_edited {
15152                    if let Some(project) = &self.project {
15153                        #[allow(clippy::mutable_key_type)]
15154                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
15155                            multibuffer
15156                                .all_buffers()
15157                                .into_iter()
15158                                .filter_map(|buffer| {
15159                                    buffer.update(cx, |buffer, cx| {
15160                                        let language = buffer.language()?;
15161                                        let should_discard = project.update(cx, |project, cx| {
15162                                            project.is_local()
15163                                                && !project.has_language_servers_for(buffer, cx)
15164                                        });
15165                                        should_discard.not().then_some(language.clone())
15166                                    })
15167                                })
15168                                .collect::<HashSet<_>>()
15169                        });
15170                        if !languages_affected.is_empty() {
15171                            self.refresh_inlay_hints(
15172                                InlayHintRefreshReason::BufferEdited(languages_affected),
15173                                cx,
15174                            );
15175                        }
15176                    }
15177                }
15178
15179                let Some(project) = &self.project else { return };
15180                let (telemetry, is_via_ssh) = {
15181                    let project = project.read(cx);
15182                    let telemetry = project.client().telemetry().clone();
15183                    let is_via_ssh = project.is_via_ssh();
15184                    (telemetry, is_via_ssh)
15185                };
15186                refresh_linked_ranges(self, window, cx);
15187                telemetry.log_edit_event("editor", is_via_ssh);
15188            }
15189            multi_buffer::Event::ExcerptsAdded {
15190                buffer,
15191                predecessor,
15192                excerpts,
15193            } => {
15194                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
15195                let buffer_id = buffer.read(cx).remote_id();
15196                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
15197                    if let Some(project) = &self.project {
15198                        get_uncommitted_diff_for_buffer(
15199                            project,
15200                            [buffer.clone()],
15201                            self.buffer.clone(),
15202                            cx,
15203                        )
15204                        .detach();
15205                    }
15206                }
15207                cx.emit(EditorEvent::ExcerptsAdded {
15208                    buffer: buffer.clone(),
15209                    predecessor: *predecessor,
15210                    excerpts: excerpts.clone(),
15211                });
15212                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
15213            }
15214            multi_buffer::Event::ExcerptsRemoved { ids } => {
15215                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
15216                let buffer = self.buffer.read(cx);
15217                self.registered_buffers
15218                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
15219                cx.emit(EditorEvent::ExcerptsRemoved { ids: ids.clone() })
15220            }
15221            multi_buffer::Event::ExcerptsEdited {
15222                excerpt_ids,
15223                buffer_ids,
15224            } => {
15225                self.display_map.update(cx, |map, cx| {
15226                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
15227                });
15228                cx.emit(EditorEvent::ExcerptsEdited {
15229                    ids: excerpt_ids.clone(),
15230                })
15231            }
15232            multi_buffer::Event::ExcerptsExpanded { ids } => {
15233                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
15234                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
15235            }
15236            multi_buffer::Event::Reparsed(buffer_id) => {
15237                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
15238
15239                cx.emit(EditorEvent::Reparsed(*buffer_id));
15240            }
15241            multi_buffer::Event::DiffHunksToggled => {
15242                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
15243            }
15244            multi_buffer::Event::LanguageChanged(buffer_id) => {
15245                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
15246                cx.emit(EditorEvent::Reparsed(*buffer_id));
15247                cx.notify();
15248            }
15249            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
15250            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
15251            multi_buffer::Event::FileHandleChanged | multi_buffer::Event::Reloaded => {
15252                cx.emit(EditorEvent::TitleChanged)
15253            }
15254            // multi_buffer::Event::DiffBaseChanged => {
15255            //     self.scrollbar_marker_state.dirty = true;
15256            //     cx.emit(EditorEvent::DiffBaseChanged);
15257            //     cx.notify();
15258            // }
15259            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
15260            multi_buffer::Event::DiagnosticsUpdated => {
15261                self.refresh_active_diagnostics(cx);
15262                self.refresh_inline_diagnostics(true, window, cx);
15263                self.scrollbar_marker_state.dirty = true;
15264                cx.notify();
15265            }
15266            _ => {}
15267        };
15268    }
15269
15270    fn on_display_map_changed(
15271        &mut self,
15272        _: Entity<DisplayMap>,
15273        _: &mut Window,
15274        cx: &mut Context<Self>,
15275    ) {
15276        cx.notify();
15277    }
15278
15279    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
15280        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
15281        self.update_edit_prediction_settings(cx);
15282        self.refresh_inline_completion(true, false, window, cx);
15283        self.refresh_inlay_hints(
15284            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
15285                self.selections.newest_anchor().head(),
15286                &self.buffer.read(cx).snapshot(cx),
15287                cx,
15288            )),
15289            cx,
15290        );
15291
15292        let old_cursor_shape = self.cursor_shape;
15293
15294        {
15295            let editor_settings = EditorSettings::get_global(cx);
15296            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
15297            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
15298            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
15299        }
15300
15301        if old_cursor_shape != self.cursor_shape {
15302            cx.emit(EditorEvent::CursorShapeChanged);
15303        }
15304
15305        let project_settings = ProjectSettings::get_global(cx);
15306        self.serialize_dirty_buffers = project_settings.session.restore_unsaved_buffers;
15307
15308        if self.mode == EditorMode::Full {
15309            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
15310            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
15311            if self.show_inline_diagnostics != show_inline_diagnostics {
15312                self.show_inline_diagnostics = show_inline_diagnostics;
15313                self.refresh_inline_diagnostics(false, window, cx);
15314            }
15315
15316            if self.git_blame_inline_enabled != inline_blame_enabled {
15317                self.toggle_git_blame_inline_internal(false, window, cx);
15318            }
15319        }
15320
15321        cx.notify();
15322    }
15323
15324    pub fn set_searchable(&mut self, searchable: bool) {
15325        self.searchable = searchable;
15326    }
15327
15328    pub fn searchable(&self) -> bool {
15329        self.searchable
15330    }
15331
15332    fn open_proposed_changes_editor(
15333        &mut self,
15334        _: &OpenProposedChangesEditor,
15335        window: &mut Window,
15336        cx: &mut Context<Self>,
15337    ) {
15338        let Some(workspace) = self.workspace() else {
15339            cx.propagate();
15340            return;
15341        };
15342
15343        let selections = self.selections.all::<usize>(cx);
15344        let multi_buffer = self.buffer.read(cx);
15345        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15346        let mut new_selections_by_buffer = HashMap::default();
15347        for selection in selections {
15348            for (buffer, range, _) in
15349                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
15350            {
15351                let mut range = range.to_point(buffer);
15352                range.start.column = 0;
15353                range.end.column = buffer.line_len(range.end.row);
15354                new_selections_by_buffer
15355                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
15356                    .or_insert(Vec::new())
15357                    .push(range)
15358            }
15359        }
15360
15361        let proposed_changes_buffers = new_selections_by_buffer
15362            .into_iter()
15363            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
15364            .collect::<Vec<_>>();
15365        let proposed_changes_editor = cx.new(|cx| {
15366            ProposedChangesEditor::new(
15367                "Proposed changes",
15368                proposed_changes_buffers,
15369                self.project.clone(),
15370                window,
15371                cx,
15372            )
15373        });
15374
15375        window.defer(cx, move |window, cx| {
15376            workspace.update(cx, |workspace, cx| {
15377                workspace.active_pane().update(cx, |pane, cx| {
15378                    pane.add_item(
15379                        Box::new(proposed_changes_editor),
15380                        true,
15381                        true,
15382                        None,
15383                        window,
15384                        cx,
15385                    );
15386                });
15387            });
15388        });
15389    }
15390
15391    pub fn open_excerpts_in_split(
15392        &mut self,
15393        _: &OpenExcerptsSplit,
15394        window: &mut Window,
15395        cx: &mut Context<Self>,
15396    ) {
15397        self.open_excerpts_common(None, true, window, cx)
15398    }
15399
15400    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
15401        self.open_excerpts_common(None, false, window, cx)
15402    }
15403
15404    fn open_excerpts_common(
15405        &mut self,
15406        jump_data: Option<JumpData>,
15407        split: bool,
15408        window: &mut Window,
15409        cx: &mut Context<Self>,
15410    ) {
15411        let Some(workspace) = self.workspace() else {
15412            cx.propagate();
15413            return;
15414        };
15415
15416        if self.buffer.read(cx).is_singleton() {
15417            cx.propagate();
15418            return;
15419        }
15420
15421        let mut new_selections_by_buffer = HashMap::default();
15422        match &jump_data {
15423            Some(JumpData::MultiBufferPoint {
15424                excerpt_id,
15425                position,
15426                anchor,
15427                line_offset_from_top,
15428            }) => {
15429                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15430                if let Some(buffer) = multi_buffer_snapshot
15431                    .buffer_id_for_excerpt(*excerpt_id)
15432                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
15433                {
15434                    let buffer_snapshot = buffer.read(cx).snapshot();
15435                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
15436                        language::ToPoint::to_point(anchor, &buffer_snapshot)
15437                    } else {
15438                        buffer_snapshot.clip_point(*position, Bias::Left)
15439                    };
15440                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
15441                    new_selections_by_buffer.insert(
15442                        buffer,
15443                        (
15444                            vec![jump_to_offset..jump_to_offset],
15445                            Some(*line_offset_from_top),
15446                        ),
15447                    );
15448                }
15449            }
15450            Some(JumpData::MultiBufferRow {
15451                row,
15452                line_offset_from_top,
15453            }) => {
15454                let point = MultiBufferPoint::new(row.0, 0);
15455                if let Some((buffer, buffer_point, _)) =
15456                    self.buffer.read(cx).point_to_buffer_point(point, cx)
15457                {
15458                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
15459                    new_selections_by_buffer
15460                        .entry(buffer)
15461                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
15462                        .0
15463                        .push(buffer_offset..buffer_offset)
15464                }
15465            }
15466            None => {
15467                let selections = self.selections.all::<usize>(cx);
15468                let multi_buffer = self.buffer.read(cx);
15469                for selection in selections {
15470                    for (snapshot, range, _, anchor) in multi_buffer
15471                        .snapshot(cx)
15472                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
15473                    {
15474                        if let Some(anchor) = anchor {
15475                            // selection is in a deleted hunk
15476                            let Some(buffer_id) = anchor.buffer_id else {
15477                                continue;
15478                            };
15479                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
15480                                continue;
15481                            };
15482                            let offset = text::ToOffset::to_offset(
15483                                &anchor.text_anchor,
15484                                &buffer_handle.read(cx).snapshot(),
15485                            );
15486                            let range = offset..offset;
15487                            new_selections_by_buffer
15488                                .entry(buffer_handle)
15489                                .or_insert((Vec::new(), None))
15490                                .0
15491                                .push(range)
15492                        } else {
15493                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
15494                            else {
15495                                continue;
15496                            };
15497                            new_selections_by_buffer
15498                                .entry(buffer_handle)
15499                                .or_insert((Vec::new(), None))
15500                                .0
15501                                .push(range)
15502                        }
15503                    }
15504                }
15505            }
15506        }
15507
15508        if new_selections_by_buffer.is_empty() {
15509            return;
15510        }
15511
15512        // We defer the pane interaction because we ourselves are a workspace item
15513        // and activating a new item causes the pane to call a method on us reentrantly,
15514        // which panics if we're on the stack.
15515        window.defer(cx, move |window, cx| {
15516            workspace.update(cx, |workspace, cx| {
15517                let pane = if split {
15518                    workspace.adjacent_pane(window, cx)
15519                } else {
15520                    workspace.active_pane().clone()
15521                };
15522
15523                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
15524                    let editor = buffer
15525                        .read(cx)
15526                        .file()
15527                        .is_none()
15528                        .then(|| {
15529                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
15530                            // so `workspace.open_project_item` will never find them, always opening a new editor.
15531                            // Instead, we try to activate the existing editor in the pane first.
15532                            let (editor, pane_item_index) =
15533                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
15534                                    let editor = item.downcast::<Editor>()?;
15535                                    let singleton_buffer =
15536                                        editor.read(cx).buffer().read(cx).as_singleton()?;
15537                                    if singleton_buffer == buffer {
15538                                        Some((editor, i))
15539                                    } else {
15540                                        None
15541                                    }
15542                                })?;
15543                            pane.update(cx, |pane, cx| {
15544                                pane.activate_item(pane_item_index, true, true, window, cx)
15545                            });
15546                            Some(editor)
15547                        })
15548                        .flatten()
15549                        .unwrap_or_else(|| {
15550                            workspace.open_project_item::<Self>(
15551                                pane.clone(),
15552                                buffer,
15553                                true,
15554                                true,
15555                                window,
15556                                cx,
15557                            )
15558                        });
15559
15560                    editor.update(cx, |editor, cx| {
15561                        let autoscroll = match scroll_offset {
15562                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
15563                            None => Autoscroll::newest(),
15564                        };
15565                        let nav_history = editor.nav_history.take();
15566                        editor.change_selections(Some(autoscroll), window, cx, |s| {
15567                            s.select_ranges(ranges);
15568                        });
15569                        editor.nav_history = nav_history;
15570                    });
15571                }
15572            })
15573        });
15574    }
15575
15576    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
15577        let snapshot = self.buffer.read(cx).read(cx);
15578        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
15579        Some(
15580            ranges
15581                .iter()
15582                .map(move |range| {
15583                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
15584                })
15585                .collect(),
15586        )
15587    }
15588
15589    fn selection_replacement_ranges(
15590        &self,
15591        range: Range<OffsetUtf16>,
15592        cx: &mut App,
15593    ) -> Vec<Range<OffsetUtf16>> {
15594        let selections = self.selections.all::<OffsetUtf16>(cx);
15595        let newest_selection = selections
15596            .iter()
15597            .max_by_key(|selection| selection.id)
15598            .unwrap();
15599        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
15600        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
15601        let snapshot = self.buffer.read(cx).read(cx);
15602        selections
15603            .into_iter()
15604            .map(|mut selection| {
15605                selection.start.0 =
15606                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
15607                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
15608                snapshot.clip_offset_utf16(selection.start, Bias::Left)
15609                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
15610            })
15611            .collect()
15612    }
15613
15614    fn report_editor_event(
15615        &self,
15616        event_type: &'static str,
15617        file_extension: Option<String>,
15618        cx: &App,
15619    ) {
15620        if cfg!(any(test, feature = "test-support")) {
15621            return;
15622        }
15623
15624        let Some(project) = &self.project else { return };
15625
15626        // If None, we are in a file without an extension
15627        let file = self
15628            .buffer
15629            .read(cx)
15630            .as_singleton()
15631            .and_then(|b| b.read(cx).file());
15632        let file_extension = file_extension.or(file
15633            .as_ref()
15634            .and_then(|file| Path::new(file.file_name(cx)).extension())
15635            .and_then(|e| e.to_str())
15636            .map(|a| a.to_string()));
15637
15638        let vim_mode = cx
15639            .global::<SettingsStore>()
15640            .raw_user_settings()
15641            .get("vim_mode")
15642            == Some(&serde_json::Value::Bool(true));
15643
15644        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
15645        let copilot_enabled = edit_predictions_provider
15646            == language::language_settings::EditPredictionProvider::Copilot;
15647        let copilot_enabled_for_language = self
15648            .buffer
15649            .read(cx)
15650            .settings_at(0, cx)
15651            .show_edit_predictions;
15652
15653        let project = project.read(cx);
15654        telemetry::event!(
15655            event_type,
15656            file_extension,
15657            vim_mode,
15658            copilot_enabled,
15659            copilot_enabled_for_language,
15660            edit_predictions_provider,
15661            is_via_ssh = project.is_via_ssh(),
15662        );
15663    }
15664
15665    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
15666    /// with each line being an array of {text, highlight} objects.
15667    fn copy_highlight_json(
15668        &mut self,
15669        _: &CopyHighlightJson,
15670        window: &mut Window,
15671        cx: &mut Context<Self>,
15672    ) {
15673        #[derive(Serialize)]
15674        struct Chunk<'a> {
15675            text: String,
15676            highlight: Option<&'a str>,
15677        }
15678
15679        let snapshot = self.buffer.read(cx).snapshot(cx);
15680        let range = self
15681            .selected_text_range(false, window, cx)
15682            .and_then(|selection| {
15683                if selection.range.is_empty() {
15684                    None
15685                } else {
15686                    Some(selection.range)
15687                }
15688            })
15689            .unwrap_or_else(|| 0..snapshot.len());
15690
15691        let chunks = snapshot.chunks(range, true);
15692        let mut lines = Vec::new();
15693        let mut line: VecDeque<Chunk> = VecDeque::new();
15694
15695        let Some(style) = self.style.as_ref() else {
15696            return;
15697        };
15698
15699        for chunk in chunks {
15700            let highlight = chunk
15701                .syntax_highlight_id
15702                .and_then(|id| id.name(&style.syntax));
15703            let mut chunk_lines = chunk.text.split('\n').peekable();
15704            while let Some(text) = chunk_lines.next() {
15705                let mut merged_with_last_token = false;
15706                if let Some(last_token) = line.back_mut() {
15707                    if last_token.highlight == highlight {
15708                        last_token.text.push_str(text);
15709                        merged_with_last_token = true;
15710                    }
15711                }
15712
15713                if !merged_with_last_token {
15714                    line.push_back(Chunk {
15715                        text: text.into(),
15716                        highlight,
15717                    });
15718                }
15719
15720                if chunk_lines.peek().is_some() {
15721                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
15722                        line.pop_front();
15723                    }
15724                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
15725                        line.pop_back();
15726                    }
15727
15728                    lines.push(mem::take(&mut line));
15729                }
15730            }
15731        }
15732
15733        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
15734            return;
15735        };
15736        cx.write_to_clipboard(ClipboardItem::new_string(lines));
15737    }
15738
15739    pub fn open_context_menu(
15740        &mut self,
15741        _: &OpenContextMenu,
15742        window: &mut Window,
15743        cx: &mut Context<Self>,
15744    ) {
15745        self.request_autoscroll(Autoscroll::newest(), cx);
15746        let position = self.selections.newest_display(cx).start;
15747        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
15748    }
15749
15750    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
15751        &self.inlay_hint_cache
15752    }
15753
15754    pub fn replay_insert_event(
15755        &mut self,
15756        text: &str,
15757        relative_utf16_range: Option<Range<isize>>,
15758        window: &mut Window,
15759        cx: &mut Context<Self>,
15760    ) {
15761        if !self.input_enabled {
15762            cx.emit(EditorEvent::InputIgnored { text: text.into() });
15763            return;
15764        }
15765        if let Some(relative_utf16_range) = relative_utf16_range {
15766            let selections = self.selections.all::<OffsetUtf16>(cx);
15767            self.change_selections(None, window, cx, |s| {
15768                let new_ranges = selections.into_iter().map(|range| {
15769                    let start = OffsetUtf16(
15770                        range
15771                            .head()
15772                            .0
15773                            .saturating_add_signed(relative_utf16_range.start),
15774                    );
15775                    let end = OffsetUtf16(
15776                        range
15777                            .head()
15778                            .0
15779                            .saturating_add_signed(relative_utf16_range.end),
15780                    );
15781                    start..end
15782                });
15783                s.select_ranges(new_ranges);
15784            });
15785        }
15786
15787        self.handle_input(text, window, cx);
15788    }
15789
15790    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
15791        let Some(provider) = self.semantics_provider.as_ref() else {
15792            return false;
15793        };
15794
15795        let mut supports = false;
15796        self.buffer().update(cx, |this, cx| {
15797            this.for_each_buffer(|buffer| {
15798                supports |= provider.supports_inlay_hints(buffer, cx);
15799            });
15800        });
15801
15802        supports
15803    }
15804
15805    pub fn is_focused(&self, window: &Window) -> bool {
15806        self.focus_handle.is_focused(window)
15807    }
15808
15809    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
15810        cx.emit(EditorEvent::Focused);
15811
15812        if let Some(descendant) = self
15813            .last_focused_descendant
15814            .take()
15815            .and_then(|descendant| descendant.upgrade())
15816        {
15817            window.focus(&descendant);
15818        } else {
15819            if let Some(blame) = self.blame.as_ref() {
15820                blame.update(cx, GitBlame::focus)
15821            }
15822
15823            self.blink_manager.update(cx, BlinkManager::enable);
15824            self.show_cursor_names(window, cx);
15825            self.buffer.update(cx, |buffer, cx| {
15826                buffer.finalize_last_transaction(cx);
15827                if self.leader_peer_id.is_none() {
15828                    buffer.set_active_selections(
15829                        &self.selections.disjoint_anchors(),
15830                        self.selections.line_mode,
15831                        self.cursor_shape,
15832                        cx,
15833                    );
15834                }
15835            });
15836        }
15837    }
15838
15839    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
15840        cx.emit(EditorEvent::FocusedIn)
15841    }
15842
15843    fn handle_focus_out(
15844        &mut self,
15845        event: FocusOutEvent,
15846        _window: &mut Window,
15847        _cx: &mut Context<Self>,
15848    ) {
15849        if event.blurred != self.focus_handle {
15850            self.last_focused_descendant = Some(event.blurred);
15851        }
15852    }
15853
15854    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
15855        self.blink_manager.update(cx, BlinkManager::disable);
15856        self.buffer
15857            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
15858
15859        if let Some(blame) = self.blame.as_ref() {
15860            blame.update(cx, GitBlame::blur)
15861        }
15862        if !self.hover_state.focused(window, cx) {
15863            hide_hover(self, cx);
15864        }
15865        if !self
15866            .context_menu
15867            .borrow()
15868            .as_ref()
15869            .is_some_and(|context_menu| context_menu.focused(window, cx))
15870        {
15871            self.hide_context_menu(window, cx);
15872        }
15873        self.discard_inline_completion(false, cx);
15874        cx.emit(EditorEvent::Blurred);
15875        cx.notify();
15876    }
15877
15878    pub fn register_action<A: Action>(
15879        &mut self,
15880        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
15881    ) -> Subscription {
15882        let id = self.next_editor_action_id.post_inc();
15883        let listener = Arc::new(listener);
15884        self.editor_actions.borrow_mut().insert(
15885            id,
15886            Box::new(move |window, _| {
15887                let listener = listener.clone();
15888                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
15889                    let action = action.downcast_ref().unwrap();
15890                    if phase == DispatchPhase::Bubble {
15891                        listener(action, window, cx)
15892                    }
15893                })
15894            }),
15895        );
15896
15897        let editor_actions = self.editor_actions.clone();
15898        Subscription::new(move || {
15899            editor_actions.borrow_mut().remove(&id);
15900        })
15901    }
15902
15903    pub fn file_header_size(&self) -> u32 {
15904        FILE_HEADER_HEIGHT
15905    }
15906
15907    pub fn restore(
15908        &mut self,
15909        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
15910        window: &mut Window,
15911        cx: &mut Context<Self>,
15912    ) {
15913        let workspace = self.workspace();
15914        let project = self.project.as_ref();
15915        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
15916            let mut tasks = Vec::new();
15917            for (buffer_id, changes) in revert_changes {
15918                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15919                    buffer.update(cx, |buffer, cx| {
15920                        buffer.edit(
15921                            changes.into_iter().map(|(range, text)| {
15922                                (range, text.to_string().map(Arc::<str>::from))
15923                            }),
15924                            None,
15925                            cx,
15926                        );
15927                    });
15928
15929                    if let Some(project) =
15930                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
15931                    {
15932                        project.update(cx, |project, cx| {
15933                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
15934                        })
15935                    }
15936                }
15937            }
15938            tasks
15939        });
15940        cx.spawn_in(window, |_, mut cx| async move {
15941            for (buffer, task) in save_tasks {
15942                let result = task.await;
15943                if result.is_err() {
15944                    let Some(path) = buffer
15945                        .read_with(&cx, |buffer, cx| buffer.project_path(cx))
15946                        .ok()
15947                    else {
15948                        continue;
15949                    };
15950                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
15951                        let Some(task) = cx
15952                            .update_window_entity(&workspace, |workspace, window, cx| {
15953                                workspace
15954                                    .open_path_preview(path, None, false, false, false, window, cx)
15955                            })
15956                            .ok()
15957                        else {
15958                            continue;
15959                        };
15960                        task.await.log_err();
15961                    }
15962                }
15963            }
15964        })
15965        .detach();
15966        self.change_selections(None, window, cx, |selections| selections.refresh());
15967    }
15968
15969    pub fn to_pixel_point(
15970        &self,
15971        source: multi_buffer::Anchor,
15972        editor_snapshot: &EditorSnapshot,
15973        window: &mut Window,
15974    ) -> Option<gpui::Point<Pixels>> {
15975        let source_point = source.to_display_point(editor_snapshot);
15976        self.display_to_pixel_point(source_point, editor_snapshot, window)
15977    }
15978
15979    pub fn display_to_pixel_point(
15980        &self,
15981        source: DisplayPoint,
15982        editor_snapshot: &EditorSnapshot,
15983        window: &mut Window,
15984    ) -> Option<gpui::Point<Pixels>> {
15985        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
15986        let text_layout_details = self.text_layout_details(window);
15987        let scroll_top = text_layout_details
15988            .scroll_anchor
15989            .scroll_position(editor_snapshot)
15990            .y;
15991
15992        if source.row().as_f32() < scroll_top.floor() {
15993            return None;
15994        }
15995        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
15996        let source_y = line_height * (source.row().as_f32() - scroll_top);
15997        Some(gpui::Point::new(source_x, source_y))
15998    }
15999
16000    pub fn has_visible_completions_menu(&self) -> bool {
16001        !self.edit_prediction_preview_is_active()
16002            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
16003                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
16004            })
16005    }
16006
16007    pub fn register_addon<T: Addon>(&mut self, instance: T) {
16008        self.addons
16009            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
16010    }
16011
16012    pub fn unregister_addon<T: Addon>(&mut self) {
16013        self.addons.remove(&std::any::TypeId::of::<T>());
16014    }
16015
16016    pub fn addon<T: Addon>(&self) -> Option<&T> {
16017        let type_id = std::any::TypeId::of::<T>();
16018        self.addons
16019            .get(&type_id)
16020            .and_then(|item| item.to_any().downcast_ref::<T>())
16021    }
16022
16023    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
16024        let text_layout_details = self.text_layout_details(window);
16025        let style = &text_layout_details.editor_style;
16026        let font_id = window.text_system().resolve_font(&style.text.font());
16027        let font_size = style.text.font_size.to_pixels(window.rem_size());
16028        let line_height = style.text.line_height_in_pixels(window.rem_size());
16029        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
16030
16031        gpui::Size::new(em_width, line_height)
16032    }
16033
16034    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
16035        self.load_diff_task.clone()
16036    }
16037
16038    fn read_selections_from_db(
16039        &mut self,
16040        item_id: u64,
16041        workspace_id: WorkspaceId,
16042        window: &mut Window,
16043        cx: &mut Context<Editor>,
16044    ) {
16045        if !self.is_singleton(cx)
16046            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
16047        {
16048            return;
16049        }
16050        let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() else {
16051            return;
16052        };
16053        if selections.is_empty() {
16054            return;
16055        }
16056
16057        let snapshot = self.buffer.read(cx).snapshot(cx);
16058        self.change_selections(None, window, cx, |s| {
16059            s.select_ranges(selections.into_iter().map(|(start, end)| {
16060                snapshot.clip_offset(start, Bias::Left)..snapshot.clip_offset(end, Bias::Right)
16061            }));
16062        });
16063    }
16064}
16065
16066fn insert_extra_newline_brackets(
16067    buffer: &MultiBufferSnapshot,
16068    range: Range<usize>,
16069    language: &language::LanguageScope,
16070) -> bool {
16071    let leading_whitespace_len = buffer
16072        .reversed_chars_at(range.start)
16073        .take_while(|c| c.is_whitespace() && *c != '\n')
16074        .map(|c| c.len_utf8())
16075        .sum::<usize>();
16076    let trailing_whitespace_len = buffer
16077        .chars_at(range.end)
16078        .take_while(|c| c.is_whitespace() && *c != '\n')
16079        .map(|c| c.len_utf8())
16080        .sum::<usize>();
16081    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
16082
16083    language.brackets().any(|(pair, enabled)| {
16084        let pair_start = pair.start.trim_end();
16085        let pair_end = pair.end.trim_start();
16086
16087        enabled
16088            && pair.newline
16089            && buffer.contains_str_at(range.end, pair_end)
16090            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
16091    })
16092}
16093
16094fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
16095    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
16096        [(buffer, range, _)] => (*buffer, range.clone()),
16097        _ => return false,
16098    };
16099    let pair = {
16100        let mut result: Option<BracketMatch> = None;
16101
16102        for pair in buffer
16103            .all_bracket_ranges(range.clone())
16104            .filter(move |pair| {
16105                pair.open_range.start <= range.start && pair.close_range.end >= range.end
16106            })
16107        {
16108            let len = pair.close_range.end - pair.open_range.start;
16109
16110            if let Some(existing) = &result {
16111                let existing_len = existing.close_range.end - existing.open_range.start;
16112                if len > existing_len {
16113                    continue;
16114                }
16115            }
16116
16117            result = Some(pair);
16118        }
16119
16120        result
16121    };
16122    let Some(pair) = pair else {
16123        return false;
16124    };
16125    pair.newline_only
16126        && buffer
16127            .chars_for_range(pair.open_range.end..range.start)
16128            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
16129            .all(|c| c.is_whitespace() && c != '\n')
16130}
16131
16132fn get_uncommitted_diff_for_buffer(
16133    project: &Entity<Project>,
16134    buffers: impl IntoIterator<Item = Entity<Buffer>>,
16135    buffer: Entity<MultiBuffer>,
16136    cx: &mut App,
16137) -> Task<()> {
16138    let mut tasks = Vec::new();
16139    project.update(cx, |project, cx| {
16140        for buffer in buffers {
16141            tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
16142        }
16143    });
16144    cx.spawn(|mut cx| async move {
16145        let diffs = futures::future::join_all(tasks).await;
16146        buffer
16147            .update(&mut cx, |buffer, cx| {
16148                for diff in diffs.into_iter().flatten() {
16149                    buffer.add_diff(diff, cx);
16150                }
16151            })
16152            .ok();
16153    })
16154}
16155
16156fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
16157    let tab_size = tab_size.get() as usize;
16158    let mut width = offset;
16159
16160    for ch in text.chars() {
16161        width += if ch == '\t' {
16162            tab_size - (width % tab_size)
16163        } else {
16164            1
16165        };
16166    }
16167
16168    width - offset
16169}
16170
16171#[cfg(test)]
16172mod tests {
16173    use super::*;
16174
16175    #[test]
16176    fn test_string_size_with_expanded_tabs() {
16177        let nz = |val| NonZeroU32::new(val).unwrap();
16178        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
16179        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
16180        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
16181        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
16182        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
16183        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
16184        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
16185        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
16186    }
16187}
16188
16189/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
16190struct WordBreakingTokenizer<'a> {
16191    input: &'a str,
16192}
16193
16194impl<'a> WordBreakingTokenizer<'a> {
16195    fn new(input: &'a str) -> Self {
16196        Self { input }
16197    }
16198}
16199
16200fn is_char_ideographic(ch: char) -> bool {
16201    use unicode_script::Script::*;
16202    use unicode_script::UnicodeScript;
16203    matches!(ch.script(), Han | Tangut | Yi)
16204}
16205
16206fn is_grapheme_ideographic(text: &str) -> bool {
16207    text.chars().any(is_char_ideographic)
16208}
16209
16210fn is_grapheme_whitespace(text: &str) -> bool {
16211    text.chars().any(|x| x.is_whitespace())
16212}
16213
16214fn should_stay_with_preceding_ideograph(text: &str) -> bool {
16215    text.chars().next().map_or(false, |ch| {
16216        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
16217    })
16218}
16219
16220#[derive(PartialEq, Eq, Debug, Clone, Copy)]
16221struct WordBreakToken<'a> {
16222    token: &'a str,
16223    grapheme_len: usize,
16224    is_whitespace: bool,
16225}
16226
16227impl<'a> Iterator for WordBreakingTokenizer<'a> {
16228    /// Yields a span, the count of graphemes in the token, and whether it was
16229    /// whitespace. Note that it also breaks at word boundaries.
16230    type Item = WordBreakToken<'a>;
16231
16232    fn next(&mut self) -> Option<Self::Item> {
16233        use unicode_segmentation::UnicodeSegmentation;
16234        if self.input.is_empty() {
16235            return None;
16236        }
16237
16238        let mut iter = self.input.graphemes(true).peekable();
16239        let mut offset = 0;
16240        let mut graphemes = 0;
16241        if let Some(first_grapheme) = iter.next() {
16242            let is_whitespace = is_grapheme_whitespace(first_grapheme);
16243            offset += first_grapheme.len();
16244            graphemes += 1;
16245            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
16246                if let Some(grapheme) = iter.peek().copied() {
16247                    if should_stay_with_preceding_ideograph(grapheme) {
16248                        offset += grapheme.len();
16249                        graphemes += 1;
16250                    }
16251                }
16252            } else {
16253                let mut words = self.input[offset..].split_word_bound_indices().peekable();
16254                let mut next_word_bound = words.peek().copied();
16255                if next_word_bound.map_or(false, |(i, _)| i == 0) {
16256                    next_word_bound = words.next();
16257                }
16258                while let Some(grapheme) = iter.peek().copied() {
16259                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
16260                        break;
16261                    };
16262                    if is_grapheme_whitespace(grapheme) != is_whitespace {
16263                        break;
16264                    };
16265                    offset += grapheme.len();
16266                    graphemes += 1;
16267                    iter.next();
16268                }
16269            }
16270            let token = &self.input[..offset];
16271            self.input = &self.input[offset..];
16272            if is_whitespace {
16273                Some(WordBreakToken {
16274                    token: " ",
16275                    grapheme_len: 1,
16276                    is_whitespace: true,
16277                })
16278            } else {
16279                Some(WordBreakToken {
16280                    token,
16281                    grapheme_len: graphemes,
16282                    is_whitespace: false,
16283                })
16284            }
16285        } else {
16286            None
16287        }
16288    }
16289}
16290
16291#[test]
16292fn test_word_breaking_tokenizer() {
16293    let tests: &[(&str, &[(&str, usize, bool)])] = &[
16294        ("", &[]),
16295        ("  ", &[(" ", 1, true)]),
16296        ("Ʒ", &[("Ʒ", 1, false)]),
16297        ("Ǽ", &[("Ǽ", 1, false)]),
16298        ("", &[("", 1, false)]),
16299        ("⋑⋑", &[("⋑⋑", 2, false)]),
16300        (
16301            "原理,进而",
16302            &[
16303                ("", 1, false),
16304                ("理,", 2, false),
16305                ("", 1, false),
16306                ("", 1, false),
16307            ],
16308        ),
16309        (
16310            "hello world",
16311            &[("hello", 5, false), (" ", 1, true), ("world", 5, false)],
16312        ),
16313        (
16314            "hello, world",
16315            &[("hello,", 6, false), (" ", 1, true), ("world", 5, false)],
16316        ),
16317        (
16318            "  hello world",
16319            &[
16320                (" ", 1, true),
16321                ("hello", 5, false),
16322                (" ", 1, true),
16323                ("world", 5, false),
16324            ],
16325        ),
16326        (
16327            "这是什么 \n 钢笔",
16328            &[
16329                ("", 1, false),
16330                ("", 1, false),
16331                ("", 1, false),
16332                ("", 1, false),
16333                (" ", 1, true),
16334                ("", 1, false),
16335                ("", 1, false),
16336            ],
16337        ),
16338        (" mutton", &[(" ", 1, true), ("mutton", 6, false)]),
16339    ];
16340
16341    for (input, result) in tests {
16342        assert_eq!(
16343            WordBreakingTokenizer::new(input).collect::<Vec<_>>(),
16344            result
16345                .iter()
16346                .copied()
16347                .map(|(token, grapheme_len, is_whitespace)| WordBreakToken {
16348                    token,
16349                    grapheme_len,
16350                    is_whitespace,
16351                })
16352                .collect::<Vec<_>>()
16353        );
16354    }
16355}
16356
16357fn wrap_with_prefix(
16358    line_prefix: String,
16359    unwrapped_text: String,
16360    wrap_column: usize,
16361    tab_size: NonZeroU32,
16362) -> String {
16363    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
16364    let mut wrapped_text = String::new();
16365    let mut current_line = line_prefix.clone();
16366
16367    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
16368    let mut current_line_len = line_prefix_len;
16369    for WordBreakToken {
16370        token,
16371        grapheme_len,
16372        is_whitespace,
16373    } in tokenizer
16374    {
16375        if current_line_len + grapheme_len > wrap_column && current_line_len != line_prefix_len {
16376            wrapped_text.push_str(current_line.trim_end());
16377            wrapped_text.push('\n');
16378            current_line.truncate(line_prefix.len());
16379            current_line_len = line_prefix_len;
16380            if !is_whitespace {
16381                current_line.push_str(token);
16382                current_line_len += grapheme_len;
16383            }
16384        } else if !is_whitespace {
16385            current_line.push_str(token);
16386            current_line_len += grapheme_len;
16387        } else if current_line_len != line_prefix_len {
16388            current_line.push(' ');
16389            current_line_len += 1;
16390        }
16391    }
16392
16393    if !current_line.is_empty() {
16394        wrapped_text.push_str(&current_line);
16395    }
16396    wrapped_text
16397}
16398
16399#[test]
16400fn test_wrap_with_prefix() {
16401    assert_eq!(
16402        wrap_with_prefix(
16403            "# ".to_string(),
16404            "abcdefg".to_string(),
16405            4,
16406            NonZeroU32::new(4).unwrap()
16407        ),
16408        "# abcdefg"
16409    );
16410    assert_eq!(
16411        wrap_with_prefix(
16412            "".to_string(),
16413            "\thello world".to_string(),
16414            8,
16415            NonZeroU32::new(4).unwrap()
16416        ),
16417        "hello\nworld"
16418    );
16419    assert_eq!(
16420        wrap_with_prefix(
16421            "// ".to_string(),
16422            "xx \nyy zz aa bb cc".to_string(),
16423            12,
16424            NonZeroU32::new(4).unwrap()
16425        ),
16426        "// xx yy zz\n// aa bb cc"
16427    );
16428    assert_eq!(
16429        wrap_with_prefix(
16430            String::new(),
16431            "这是什么 \n 钢笔".to_string(),
16432            3,
16433            NonZeroU32::new(4).unwrap()
16434        ),
16435        "这是什\n么 钢\n"
16436    );
16437}
16438
16439pub trait CollaborationHub {
16440    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
16441    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
16442    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
16443}
16444
16445impl CollaborationHub for Entity<Project> {
16446    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
16447        self.read(cx).collaborators()
16448    }
16449
16450    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
16451        self.read(cx).user_store().read(cx).participant_indices()
16452    }
16453
16454    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
16455        let this = self.read(cx);
16456        let user_ids = this.collaborators().values().map(|c| c.user_id);
16457        this.user_store().read_with(cx, |user_store, cx| {
16458            user_store.participant_names(user_ids, cx)
16459        })
16460    }
16461}
16462
16463pub trait SemanticsProvider {
16464    fn hover(
16465        &self,
16466        buffer: &Entity<Buffer>,
16467        position: text::Anchor,
16468        cx: &mut App,
16469    ) -> Option<Task<Vec<project::Hover>>>;
16470
16471    fn inlay_hints(
16472        &self,
16473        buffer_handle: Entity<Buffer>,
16474        range: Range<text::Anchor>,
16475        cx: &mut App,
16476    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
16477
16478    fn resolve_inlay_hint(
16479        &self,
16480        hint: InlayHint,
16481        buffer_handle: Entity<Buffer>,
16482        server_id: LanguageServerId,
16483        cx: &mut App,
16484    ) -> Option<Task<anyhow::Result<InlayHint>>>;
16485
16486    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
16487
16488    fn document_highlights(
16489        &self,
16490        buffer: &Entity<Buffer>,
16491        position: text::Anchor,
16492        cx: &mut App,
16493    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
16494
16495    fn definitions(
16496        &self,
16497        buffer: &Entity<Buffer>,
16498        position: text::Anchor,
16499        kind: GotoDefinitionKind,
16500        cx: &mut App,
16501    ) -> Option<Task<Result<Vec<LocationLink>>>>;
16502
16503    fn range_for_rename(
16504        &self,
16505        buffer: &Entity<Buffer>,
16506        position: text::Anchor,
16507        cx: &mut App,
16508    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
16509
16510    fn perform_rename(
16511        &self,
16512        buffer: &Entity<Buffer>,
16513        position: text::Anchor,
16514        new_name: String,
16515        cx: &mut App,
16516    ) -> Option<Task<Result<ProjectTransaction>>>;
16517}
16518
16519pub trait CompletionProvider {
16520    fn completions(
16521        &self,
16522        buffer: &Entity<Buffer>,
16523        buffer_position: text::Anchor,
16524        trigger: CompletionContext,
16525        window: &mut Window,
16526        cx: &mut Context<Editor>,
16527    ) -> Task<Result<Vec<Completion>>>;
16528
16529    fn resolve_completions(
16530        &self,
16531        buffer: Entity<Buffer>,
16532        completion_indices: Vec<usize>,
16533        completions: Rc<RefCell<Box<[Completion]>>>,
16534        cx: &mut Context<Editor>,
16535    ) -> Task<Result<bool>>;
16536
16537    fn apply_additional_edits_for_completion(
16538        &self,
16539        _buffer: Entity<Buffer>,
16540        _completions: Rc<RefCell<Box<[Completion]>>>,
16541        _completion_index: usize,
16542        _push_to_history: bool,
16543        _cx: &mut Context<Editor>,
16544    ) -> Task<Result<Option<language::Transaction>>> {
16545        Task::ready(Ok(None))
16546    }
16547
16548    fn is_completion_trigger(
16549        &self,
16550        buffer: &Entity<Buffer>,
16551        position: language::Anchor,
16552        text: &str,
16553        trigger_in_words: bool,
16554        cx: &mut Context<Editor>,
16555    ) -> bool;
16556
16557    fn sort_completions(&self) -> bool {
16558        true
16559    }
16560}
16561
16562pub trait CodeActionProvider {
16563    fn id(&self) -> Arc<str>;
16564
16565    fn code_actions(
16566        &self,
16567        buffer: &Entity<Buffer>,
16568        range: Range<text::Anchor>,
16569        window: &mut Window,
16570        cx: &mut App,
16571    ) -> Task<Result<Vec<CodeAction>>>;
16572
16573    fn apply_code_action(
16574        &self,
16575        buffer_handle: Entity<Buffer>,
16576        action: CodeAction,
16577        excerpt_id: ExcerptId,
16578        push_to_history: bool,
16579        window: &mut Window,
16580        cx: &mut App,
16581    ) -> Task<Result<ProjectTransaction>>;
16582}
16583
16584impl CodeActionProvider for Entity<Project> {
16585    fn id(&self) -> Arc<str> {
16586        "project".into()
16587    }
16588
16589    fn code_actions(
16590        &self,
16591        buffer: &Entity<Buffer>,
16592        range: Range<text::Anchor>,
16593        _window: &mut Window,
16594        cx: &mut App,
16595    ) -> Task<Result<Vec<CodeAction>>> {
16596        self.update(cx, |project, cx| {
16597            project.code_actions(buffer, range, None, cx)
16598        })
16599    }
16600
16601    fn apply_code_action(
16602        &self,
16603        buffer_handle: Entity<Buffer>,
16604        action: CodeAction,
16605        _excerpt_id: ExcerptId,
16606        push_to_history: bool,
16607        _window: &mut Window,
16608        cx: &mut App,
16609    ) -> Task<Result<ProjectTransaction>> {
16610        self.update(cx, |project, cx| {
16611            project.apply_code_action(buffer_handle, action, push_to_history, cx)
16612        })
16613    }
16614}
16615
16616fn snippet_completions(
16617    project: &Project,
16618    buffer: &Entity<Buffer>,
16619    buffer_position: text::Anchor,
16620    cx: &mut App,
16621) -> Task<Result<Vec<Completion>>> {
16622    let language = buffer.read(cx).language_at(buffer_position);
16623    let language_name = language.as_ref().map(|language| language.lsp_id());
16624    let snippet_store = project.snippets().read(cx);
16625    let snippets = snippet_store.snippets_for(language_name, cx);
16626
16627    if snippets.is_empty() {
16628        return Task::ready(Ok(vec![]));
16629    }
16630    let snapshot = buffer.read(cx).text_snapshot();
16631    let chars: String = snapshot
16632        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
16633        .collect();
16634
16635    let scope = language.map(|language| language.default_scope());
16636    let executor = cx.background_executor().clone();
16637
16638    cx.background_spawn(async move {
16639        let classifier = CharClassifier::new(scope).for_completion(true);
16640        let mut last_word = chars
16641            .chars()
16642            .take_while(|c| classifier.is_word(*c))
16643            .collect::<String>();
16644        last_word = last_word.chars().rev().collect();
16645
16646        if last_word.is_empty() {
16647            return Ok(vec![]);
16648        }
16649
16650        let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
16651        let to_lsp = |point: &text::Anchor| {
16652            let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
16653            point_to_lsp(end)
16654        };
16655        let lsp_end = to_lsp(&buffer_position);
16656
16657        let candidates = snippets
16658            .iter()
16659            .enumerate()
16660            .flat_map(|(ix, snippet)| {
16661                snippet
16662                    .prefix
16663                    .iter()
16664                    .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
16665            })
16666            .collect::<Vec<StringMatchCandidate>>();
16667
16668        let mut matches = fuzzy::match_strings(
16669            &candidates,
16670            &last_word,
16671            last_word.chars().any(|c| c.is_uppercase()),
16672            100,
16673            &Default::default(),
16674            executor,
16675        )
16676        .await;
16677
16678        // Remove all candidates where the query's start does not match the start of any word in the candidate
16679        if let Some(query_start) = last_word.chars().next() {
16680            matches.retain(|string_match| {
16681                split_words(&string_match.string).any(|word| {
16682                    // Check that the first codepoint of the word as lowercase matches the first
16683                    // codepoint of the query as lowercase
16684                    word.chars()
16685                        .flat_map(|codepoint| codepoint.to_lowercase())
16686                        .zip(query_start.to_lowercase())
16687                        .all(|(word_cp, query_cp)| word_cp == query_cp)
16688                })
16689            });
16690        }
16691
16692        let matched_strings = matches
16693            .into_iter()
16694            .map(|m| m.string)
16695            .collect::<HashSet<_>>();
16696
16697        let result: Vec<Completion> = snippets
16698            .into_iter()
16699            .filter_map(|snippet| {
16700                let matching_prefix = snippet
16701                    .prefix
16702                    .iter()
16703                    .find(|prefix| matched_strings.contains(*prefix))?;
16704                let start = as_offset - last_word.len();
16705                let start = snapshot.anchor_before(start);
16706                let range = start..buffer_position;
16707                let lsp_start = to_lsp(&start);
16708                let lsp_range = lsp::Range {
16709                    start: lsp_start,
16710                    end: lsp_end,
16711                };
16712                Some(Completion {
16713                    old_range: range,
16714                    new_text: snippet.body.clone(),
16715                    resolved: false,
16716                    label: CodeLabel {
16717                        text: matching_prefix.clone(),
16718                        runs: vec![],
16719                        filter_range: 0..matching_prefix.len(),
16720                    },
16721                    server_id: LanguageServerId(usize::MAX),
16722                    documentation: snippet
16723                        .description
16724                        .clone()
16725                        .map(|description| CompletionDocumentation::SingleLine(description.into())),
16726                    lsp_completion: lsp::CompletionItem {
16727                        label: snippet.prefix.first().unwrap().clone(),
16728                        kind: Some(CompletionItemKind::SNIPPET),
16729                        label_details: snippet.description.as_ref().map(|description| {
16730                            lsp::CompletionItemLabelDetails {
16731                                detail: Some(description.clone()),
16732                                description: None,
16733                            }
16734                        }),
16735                        insert_text_format: Some(InsertTextFormat::SNIPPET),
16736                        text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
16737                            lsp::InsertReplaceEdit {
16738                                new_text: snippet.body.clone(),
16739                                insert: lsp_range,
16740                                replace: lsp_range,
16741                            },
16742                        )),
16743                        filter_text: Some(snippet.body.clone()),
16744                        sort_text: Some(char::MAX.to_string()),
16745                        ..Default::default()
16746                    },
16747                    confirm: None,
16748                })
16749            })
16750            .collect();
16751
16752        Ok(result)
16753    })
16754}
16755
16756impl CompletionProvider for Entity<Project> {
16757    fn completions(
16758        &self,
16759        buffer: &Entity<Buffer>,
16760        buffer_position: text::Anchor,
16761        options: CompletionContext,
16762        _window: &mut Window,
16763        cx: &mut Context<Editor>,
16764    ) -> Task<Result<Vec<Completion>>> {
16765        self.update(cx, |project, cx| {
16766            let snippets = snippet_completions(project, buffer, buffer_position, cx);
16767            let project_completions = project.completions(buffer, buffer_position, options, cx);
16768            cx.background_spawn(async move {
16769                let mut completions = project_completions.await?;
16770                let snippets_completions = snippets.await?;
16771                completions.extend(snippets_completions);
16772                Ok(completions)
16773            })
16774        })
16775    }
16776
16777    fn resolve_completions(
16778        &self,
16779        buffer: Entity<Buffer>,
16780        completion_indices: Vec<usize>,
16781        completions: Rc<RefCell<Box<[Completion]>>>,
16782        cx: &mut Context<Editor>,
16783    ) -> Task<Result<bool>> {
16784        self.update(cx, |project, cx| {
16785            project.lsp_store().update(cx, |lsp_store, cx| {
16786                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
16787            })
16788        })
16789    }
16790
16791    fn apply_additional_edits_for_completion(
16792        &self,
16793        buffer: Entity<Buffer>,
16794        completions: Rc<RefCell<Box<[Completion]>>>,
16795        completion_index: usize,
16796        push_to_history: bool,
16797        cx: &mut Context<Editor>,
16798    ) -> Task<Result<Option<language::Transaction>>> {
16799        self.update(cx, |project, cx| {
16800            project.lsp_store().update(cx, |lsp_store, cx| {
16801                lsp_store.apply_additional_edits_for_completion(
16802                    buffer,
16803                    completions,
16804                    completion_index,
16805                    push_to_history,
16806                    cx,
16807                )
16808            })
16809        })
16810    }
16811
16812    fn is_completion_trigger(
16813        &self,
16814        buffer: &Entity<Buffer>,
16815        position: language::Anchor,
16816        text: &str,
16817        trigger_in_words: bool,
16818        cx: &mut Context<Editor>,
16819    ) -> bool {
16820        let mut chars = text.chars();
16821        let char = if let Some(char) = chars.next() {
16822            char
16823        } else {
16824            return false;
16825        };
16826        if chars.next().is_some() {
16827            return false;
16828        }
16829
16830        let buffer = buffer.read(cx);
16831        let snapshot = buffer.snapshot();
16832        if !snapshot.settings_at(position, cx).show_completions_on_input {
16833            return false;
16834        }
16835        let classifier = snapshot.char_classifier_at(position).for_completion(true);
16836        if trigger_in_words && classifier.is_word(char) {
16837            return true;
16838        }
16839
16840        buffer.completion_triggers().contains(text)
16841    }
16842}
16843
16844impl SemanticsProvider for Entity<Project> {
16845    fn hover(
16846        &self,
16847        buffer: &Entity<Buffer>,
16848        position: text::Anchor,
16849        cx: &mut App,
16850    ) -> Option<Task<Vec<project::Hover>>> {
16851        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
16852    }
16853
16854    fn document_highlights(
16855        &self,
16856        buffer: &Entity<Buffer>,
16857        position: text::Anchor,
16858        cx: &mut App,
16859    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
16860        Some(self.update(cx, |project, cx| {
16861            project.document_highlights(buffer, position, cx)
16862        }))
16863    }
16864
16865    fn definitions(
16866        &self,
16867        buffer: &Entity<Buffer>,
16868        position: text::Anchor,
16869        kind: GotoDefinitionKind,
16870        cx: &mut App,
16871    ) -> Option<Task<Result<Vec<LocationLink>>>> {
16872        Some(self.update(cx, |project, cx| match kind {
16873            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
16874            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
16875            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
16876            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
16877        }))
16878    }
16879
16880    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
16881        // TODO: make this work for remote projects
16882        self.update(cx, |this, cx| {
16883            buffer.update(cx, |buffer, cx| {
16884                this.any_language_server_supports_inlay_hints(buffer, cx)
16885            })
16886        })
16887    }
16888
16889    fn inlay_hints(
16890        &self,
16891        buffer_handle: Entity<Buffer>,
16892        range: Range<text::Anchor>,
16893        cx: &mut App,
16894    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
16895        Some(self.update(cx, |project, cx| {
16896            project.inlay_hints(buffer_handle, range, cx)
16897        }))
16898    }
16899
16900    fn resolve_inlay_hint(
16901        &self,
16902        hint: InlayHint,
16903        buffer_handle: Entity<Buffer>,
16904        server_id: LanguageServerId,
16905        cx: &mut App,
16906    ) -> Option<Task<anyhow::Result<InlayHint>>> {
16907        Some(self.update(cx, |project, cx| {
16908            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
16909        }))
16910    }
16911
16912    fn range_for_rename(
16913        &self,
16914        buffer: &Entity<Buffer>,
16915        position: text::Anchor,
16916        cx: &mut App,
16917    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
16918        Some(self.update(cx, |project, cx| {
16919            let buffer = buffer.clone();
16920            let task = project.prepare_rename(buffer.clone(), position, cx);
16921            cx.spawn(|_, mut cx| async move {
16922                Ok(match task.await? {
16923                    PrepareRenameResponse::Success(range) => Some(range),
16924                    PrepareRenameResponse::InvalidPosition => None,
16925                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
16926                        // Fallback on using TreeSitter info to determine identifier range
16927                        buffer.update(&mut cx, |buffer, _| {
16928                            let snapshot = buffer.snapshot();
16929                            let (range, kind) = snapshot.surrounding_word(position);
16930                            if kind != Some(CharKind::Word) {
16931                                return None;
16932                            }
16933                            Some(
16934                                snapshot.anchor_before(range.start)
16935                                    ..snapshot.anchor_after(range.end),
16936                            )
16937                        })?
16938                    }
16939                })
16940            })
16941        }))
16942    }
16943
16944    fn perform_rename(
16945        &self,
16946        buffer: &Entity<Buffer>,
16947        position: text::Anchor,
16948        new_name: String,
16949        cx: &mut App,
16950    ) -> Option<Task<Result<ProjectTransaction>>> {
16951        Some(self.update(cx, |project, cx| {
16952            project.perform_rename(buffer.clone(), position, new_name, cx)
16953        }))
16954    }
16955}
16956
16957fn inlay_hint_settings(
16958    location: Anchor,
16959    snapshot: &MultiBufferSnapshot,
16960    cx: &mut Context<Editor>,
16961) -> InlayHintSettings {
16962    let file = snapshot.file_at(location);
16963    let language = snapshot.language_at(location).map(|l| l.name());
16964    language_settings(language, file, cx).inlay_hints
16965}
16966
16967fn consume_contiguous_rows(
16968    contiguous_row_selections: &mut Vec<Selection<Point>>,
16969    selection: &Selection<Point>,
16970    display_map: &DisplaySnapshot,
16971    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
16972) -> (MultiBufferRow, MultiBufferRow) {
16973    contiguous_row_selections.push(selection.clone());
16974    let start_row = MultiBufferRow(selection.start.row);
16975    let mut end_row = ending_row(selection, display_map);
16976
16977    while let Some(next_selection) = selections.peek() {
16978        if next_selection.start.row <= end_row.0 {
16979            end_row = ending_row(next_selection, display_map);
16980            contiguous_row_selections.push(selections.next().unwrap().clone());
16981        } else {
16982            break;
16983        }
16984    }
16985    (start_row, end_row)
16986}
16987
16988fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
16989    if next_selection.end.column > 0 || next_selection.is_empty() {
16990        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
16991    } else {
16992        MultiBufferRow(next_selection.end.row)
16993    }
16994}
16995
16996impl EditorSnapshot {
16997    pub fn remote_selections_in_range<'a>(
16998        &'a self,
16999        range: &'a Range<Anchor>,
17000        collaboration_hub: &dyn CollaborationHub,
17001        cx: &'a App,
17002    ) -> impl 'a + Iterator<Item = RemoteSelection> {
17003        let participant_names = collaboration_hub.user_names(cx);
17004        let participant_indices = collaboration_hub.user_participant_indices(cx);
17005        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
17006        let collaborators_by_replica_id = collaborators_by_peer_id
17007            .iter()
17008            .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
17009            .collect::<HashMap<_, _>>();
17010        self.buffer_snapshot
17011            .selections_in_range(range, false)
17012            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
17013                let collaborator = collaborators_by_replica_id.get(&replica_id)?;
17014                let participant_index = participant_indices.get(&collaborator.user_id).copied();
17015                let user_name = participant_names.get(&collaborator.user_id).cloned();
17016                Some(RemoteSelection {
17017                    replica_id,
17018                    selection,
17019                    cursor_shape,
17020                    line_mode,
17021                    participant_index,
17022                    peer_id: collaborator.peer_id,
17023                    user_name,
17024                })
17025            })
17026    }
17027
17028    pub fn hunks_for_ranges(
17029        &self,
17030        ranges: impl Iterator<Item = Range<Point>>,
17031    ) -> Vec<MultiBufferDiffHunk> {
17032        let mut hunks = Vec::new();
17033        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
17034            HashMap::default();
17035        for query_range in ranges {
17036            let query_rows =
17037                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
17038            for hunk in self.buffer_snapshot.diff_hunks_in_range(
17039                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
17040            ) {
17041                // Deleted hunk is an empty row range, no caret can be placed there and Zed allows to revert it
17042                // when the caret is just above or just below the deleted hunk.
17043                let allow_adjacent = hunk.status().is_deleted();
17044                let related_to_selection = if allow_adjacent {
17045                    hunk.row_range.overlaps(&query_rows)
17046                        || hunk.row_range.start == query_rows.end
17047                        || hunk.row_range.end == query_rows.start
17048                } else {
17049                    hunk.row_range.overlaps(&query_rows)
17050                };
17051                if related_to_selection {
17052                    if !processed_buffer_rows
17053                        .entry(hunk.buffer_id)
17054                        .or_default()
17055                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
17056                    {
17057                        continue;
17058                    }
17059                    hunks.push(hunk);
17060                }
17061            }
17062        }
17063
17064        hunks
17065    }
17066
17067    fn display_diff_hunks_for_rows<'a>(
17068        &'a self,
17069        display_rows: Range<DisplayRow>,
17070        folded_buffers: &'a HashSet<BufferId>,
17071    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
17072        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
17073        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
17074
17075        self.buffer_snapshot
17076            .diff_hunks_in_range(buffer_start..buffer_end)
17077            .filter_map(|hunk| {
17078                if folded_buffers.contains(&hunk.buffer_id) {
17079                    return None;
17080                }
17081
17082                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
17083                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
17084
17085                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
17086                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
17087
17088                let display_hunk = if hunk_display_start.column() != 0 {
17089                    DisplayDiffHunk::Folded {
17090                        display_row: hunk_display_start.row(),
17091                    }
17092                } else {
17093                    let mut end_row = hunk_display_end.row();
17094                    if hunk_display_end.column() > 0 {
17095                        end_row.0 += 1;
17096                    }
17097                    DisplayDiffHunk::Unfolded {
17098                        status: hunk.status(),
17099                        diff_base_byte_range: hunk.diff_base_byte_range,
17100                        display_row_range: hunk_display_start.row()..end_row,
17101                        multi_buffer_range: Anchor::range_in_buffer(
17102                            hunk.excerpt_id,
17103                            hunk.buffer_id,
17104                            hunk.buffer_range,
17105                        ),
17106                    }
17107                };
17108
17109                Some(display_hunk)
17110            })
17111    }
17112
17113    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
17114        self.display_snapshot.buffer_snapshot.language_at(position)
17115    }
17116
17117    pub fn is_focused(&self) -> bool {
17118        self.is_focused
17119    }
17120
17121    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
17122        self.placeholder_text.as_ref()
17123    }
17124
17125    pub fn scroll_position(&self) -> gpui::Point<f32> {
17126        self.scroll_anchor.scroll_position(&self.display_snapshot)
17127    }
17128
17129    fn gutter_dimensions(
17130        &self,
17131        font_id: FontId,
17132        font_size: Pixels,
17133        max_line_number_width: Pixels,
17134        cx: &App,
17135    ) -> Option<GutterDimensions> {
17136        if !self.show_gutter {
17137            return None;
17138        }
17139
17140        let descent = cx.text_system().descent(font_id, font_size);
17141        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
17142        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
17143
17144        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
17145            matches!(
17146                ProjectSettings::get_global(cx).git.git_gutter,
17147                Some(GitGutterSetting::TrackedFiles)
17148            )
17149        });
17150        let gutter_settings = EditorSettings::get_global(cx).gutter;
17151        let show_line_numbers = self
17152            .show_line_numbers
17153            .unwrap_or(gutter_settings.line_numbers);
17154        let line_gutter_width = if show_line_numbers {
17155            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
17156            let min_width_for_number_on_gutter = em_advance * 4.0;
17157            max_line_number_width.max(min_width_for_number_on_gutter)
17158        } else {
17159            0.0.into()
17160        };
17161
17162        let show_code_actions = self
17163            .show_code_actions
17164            .unwrap_or(gutter_settings.code_actions);
17165
17166        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
17167
17168        let git_blame_entries_width =
17169            self.git_blame_gutter_max_author_length
17170                .map(|max_author_length| {
17171                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
17172
17173                    /// The number of characters to dedicate to gaps and margins.
17174                    const SPACING_WIDTH: usize = 4;
17175
17176                    let max_char_count = max_author_length
17177                        .min(GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED)
17178                        + ::git::SHORT_SHA_LENGTH
17179                        + MAX_RELATIVE_TIMESTAMP.len()
17180                        + SPACING_WIDTH;
17181
17182                    em_advance * max_char_count
17183                });
17184
17185        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
17186        left_padding += if show_code_actions || show_runnables {
17187            em_width * 3.0
17188        } else if show_git_gutter && show_line_numbers {
17189            em_width * 2.0
17190        } else if show_git_gutter || show_line_numbers {
17191            em_width
17192        } else {
17193            px(0.)
17194        };
17195
17196        let right_padding = if gutter_settings.folds && show_line_numbers {
17197            em_width * 4.0
17198        } else if gutter_settings.folds {
17199            em_width * 3.0
17200        } else if show_line_numbers {
17201            em_width
17202        } else {
17203            px(0.)
17204        };
17205
17206        Some(GutterDimensions {
17207            left_padding,
17208            right_padding,
17209            width: line_gutter_width + left_padding + right_padding,
17210            margin: -descent,
17211            git_blame_entries_width,
17212        })
17213    }
17214
17215    pub fn render_crease_toggle(
17216        &self,
17217        buffer_row: MultiBufferRow,
17218        row_contains_cursor: bool,
17219        editor: Entity<Editor>,
17220        window: &mut Window,
17221        cx: &mut App,
17222    ) -> Option<AnyElement> {
17223        let folded = self.is_line_folded(buffer_row);
17224        let mut is_foldable = false;
17225
17226        if let Some(crease) = self
17227            .crease_snapshot
17228            .query_row(buffer_row, &self.buffer_snapshot)
17229        {
17230            is_foldable = true;
17231            match crease {
17232                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
17233                    if let Some(render_toggle) = render_toggle {
17234                        let toggle_callback =
17235                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
17236                                if folded {
17237                                    editor.update(cx, |editor, cx| {
17238                                        editor.fold_at(&crate::FoldAt { buffer_row }, window, cx)
17239                                    });
17240                                } else {
17241                                    editor.update(cx, |editor, cx| {
17242                                        editor.unfold_at(
17243                                            &crate::UnfoldAt { buffer_row },
17244                                            window,
17245                                            cx,
17246                                        )
17247                                    });
17248                                }
17249                            });
17250                        return Some((render_toggle)(
17251                            buffer_row,
17252                            folded,
17253                            toggle_callback,
17254                            window,
17255                            cx,
17256                        ));
17257                    }
17258                }
17259            }
17260        }
17261
17262        is_foldable |= self.starts_indent(buffer_row);
17263
17264        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
17265            Some(
17266                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
17267                    .toggle_state(folded)
17268                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
17269                        if folded {
17270                            this.unfold_at(&UnfoldAt { buffer_row }, window, cx);
17271                        } else {
17272                            this.fold_at(&FoldAt { buffer_row }, window, cx);
17273                        }
17274                    }))
17275                    .into_any_element(),
17276            )
17277        } else {
17278            None
17279        }
17280    }
17281
17282    pub fn render_crease_trailer(
17283        &self,
17284        buffer_row: MultiBufferRow,
17285        window: &mut Window,
17286        cx: &mut App,
17287    ) -> Option<AnyElement> {
17288        let folded = self.is_line_folded(buffer_row);
17289        if let Crease::Inline { render_trailer, .. } = self
17290            .crease_snapshot
17291            .query_row(buffer_row, &self.buffer_snapshot)?
17292        {
17293            let render_trailer = render_trailer.as_ref()?;
17294            Some(render_trailer(buffer_row, folded, window, cx))
17295        } else {
17296            None
17297        }
17298    }
17299}
17300
17301impl Deref for EditorSnapshot {
17302    type Target = DisplaySnapshot;
17303
17304    fn deref(&self) -> &Self::Target {
17305        &self.display_snapshot
17306    }
17307}
17308
17309#[derive(Clone, Debug, PartialEq, Eq)]
17310pub enum EditorEvent {
17311    InputIgnored {
17312        text: Arc<str>,
17313    },
17314    InputHandled {
17315        utf16_range_to_replace: Option<Range<isize>>,
17316        text: Arc<str>,
17317    },
17318    ExcerptsAdded {
17319        buffer: Entity<Buffer>,
17320        predecessor: ExcerptId,
17321        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
17322    },
17323    ExcerptsRemoved {
17324        ids: Vec<ExcerptId>,
17325    },
17326    BufferFoldToggled {
17327        ids: Vec<ExcerptId>,
17328        folded: bool,
17329    },
17330    ExcerptsEdited {
17331        ids: Vec<ExcerptId>,
17332    },
17333    ExcerptsExpanded {
17334        ids: Vec<ExcerptId>,
17335    },
17336    BufferEdited,
17337    Edited {
17338        transaction_id: clock::Lamport,
17339    },
17340    Reparsed(BufferId),
17341    Focused,
17342    FocusedIn,
17343    Blurred,
17344    DirtyChanged,
17345    Saved,
17346    TitleChanged,
17347    DiffBaseChanged,
17348    SelectionsChanged {
17349        local: bool,
17350    },
17351    ScrollPositionChanged {
17352        local: bool,
17353        autoscroll: bool,
17354    },
17355    Closed,
17356    TransactionUndone {
17357        transaction_id: clock::Lamport,
17358    },
17359    TransactionBegun {
17360        transaction_id: clock::Lamport,
17361    },
17362    Reloaded,
17363    CursorShapeChanged,
17364}
17365
17366impl EventEmitter<EditorEvent> for Editor {}
17367
17368impl Focusable for Editor {
17369    fn focus_handle(&self, _cx: &App) -> FocusHandle {
17370        self.focus_handle.clone()
17371    }
17372}
17373
17374impl Render for Editor {
17375    fn render<'a>(&mut self, _: &mut Window, cx: &mut Context<'a, Self>) -> impl IntoElement {
17376        let settings = ThemeSettings::get_global(cx);
17377
17378        let mut text_style = match self.mode {
17379            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
17380                color: cx.theme().colors().editor_foreground,
17381                font_family: settings.ui_font.family.clone(),
17382                font_features: settings.ui_font.features.clone(),
17383                font_fallbacks: settings.ui_font.fallbacks.clone(),
17384                font_size: rems(0.875).into(),
17385                font_weight: settings.ui_font.weight,
17386                line_height: relative(settings.buffer_line_height.value()),
17387                ..Default::default()
17388            },
17389            EditorMode::Full => TextStyle {
17390                color: cx.theme().colors().editor_foreground,
17391                font_family: settings.buffer_font.family.clone(),
17392                font_features: settings.buffer_font.features.clone(),
17393                font_fallbacks: settings.buffer_font.fallbacks.clone(),
17394                font_size: settings.buffer_font_size(cx).into(),
17395                font_weight: settings.buffer_font.weight,
17396                line_height: relative(settings.buffer_line_height.value()),
17397                ..Default::default()
17398            },
17399        };
17400        if let Some(text_style_refinement) = &self.text_style_refinement {
17401            text_style.refine(text_style_refinement)
17402        }
17403
17404        let background = match self.mode {
17405            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
17406            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
17407            EditorMode::Full => cx.theme().colors().editor_background,
17408        };
17409
17410        EditorElement::new(
17411            &cx.entity(),
17412            EditorStyle {
17413                background,
17414                local_player: cx.theme().players().local(),
17415                text: text_style,
17416                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
17417                syntax: cx.theme().syntax().clone(),
17418                status: cx.theme().status().clone(),
17419                inlay_hints_style: make_inlay_hints_style(cx),
17420                inline_completion_styles: make_suggestion_styles(cx),
17421                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
17422            },
17423        )
17424    }
17425}
17426
17427impl EntityInputHandler for Editor {
17428    fn text_for_range(
17429        &mut self,
17430        range_utf16: Range<usize>,
17431        adjusted_range: &mut Option<Range<usize>>,
17432        _: &mut Window,
17433        cx: &mut Context<Self>,
17434    ) -> Option<String> {
17435        let snapshot = self.buffer.read(cx).read(cx);
17436        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
17437        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
17438        if (start.0..end.0) != range_utf16 {
17439            adjusted_range.replace(start.0..end.0);
17440        }
17441        Some(snapshot.text_for_range(start..end).collect())
17442    }
17443
17444    fn selected_text_range(
17445        &mut self,
17446        ignore_disabled_input: bool,
17447        _: &mut Window,
17448        cx: &mut Context<Self>,
17449    ) -> Option<UTF16Selection> {
17450        // Prevent the IME menu from appearing when holding down an alphabetic key
17451        // while input is disabled.
17452        if !ignore_disabled_input && !self.input_enabled {
17453            return None;
17454        }
17455
17456        let selection = self.selections.newest::<OffsetUtf16>(cx);
17457        let range = selection.range();
17458
17459        Some(UTF16Selection {
17460            range: range.start.0..range.end.0,
17461            reversed: selection.reversed,
17462        })
17463    }
17464
17465    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
17466        let snapshot = self.buffer.read(cx).read(cx);
17467        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
17468        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
17469    }
17470
17471    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
17472        self.clear_highlights::<InputComposition>(cx);
17473        self.ime_transaction.take();
17474    }
17475
17476    fn replace_text_in_range(
17477        &mut self,
17478        range_utf16: Option<Range<usize>>,
17479        text: &str,
17480        window: &mut Window,
17481        cx: &mut Context<Self>,
17482    ) {
17483        if !self.input_enabled {
17484            cx.emit(EditorEvent::InputIgnored { text: text.into() });
17485            return;
17486        }
17487
17488        self.transact(window, cx, |this, window, cx| {
17489            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
17490                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
17491                Some(this.selection_replacement_ranges(range_utf16, cx))
17492            } else {
17493                this.marked_text_ranges(cx)
17494            };
17495
17496            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
17497                let newest_selection_id = this.selections.newest_anchor().id;
17498                this.selections
17499                    .all::<OffsetUtf16>(cx)
17500                    .iter()
17501                    .zip(ranges_to_replace.iter())
17502                    .find_map(|(selection, range)| {
17503                        if selection.id == newest_selection_id {
17504                            Some(
17505                                (range.start.0 as isize - selection.head().0 as isize)
17506                                    ..(range.end.0 as isize - selection.head().0 as isize),
17507                            )
17508                        } else {
17509                            None
17510                        }
17511                    })
17512            });
17513
17514            cx.emit(EditorEvent::InputHandled {
17515                utf16_range_to_replace: range_to_replace,
17516                text: text.into(),
17517            });
17518
17519            if let Some(new_selected_ranges) = new_selected_ranges {
17520                this.change_selections(None, window, cx, |selections| {
17521                    selections.select_ranges(new_selected_ranges)
17522                });
17523                this.backspace(&Default::default(), window, cx);
17524            }
17525
17526            this.handle_input(text, window, cx);
17527        });
17528
17529        if let Some(transaction) = self.ime_transaction {
17530            self.buffer.update(cx, |buffer, cx| {
17531                buffer.group_until_transaction(transaction, cx);
17532            });
17533        }
17534
17535        self.unmark_text(window, cx);
17536    }
17537
17538    fn replace_and_mark_text_in_range(
17539        &mut self,
17540        range_utf16: Option<Range<usize>>,
17541        text: &str,
17542        new_selected_range_utf16: Option<Range<usize>>,
17543        window: &mut Window,
17544        cx: &mut Context<Self>,
17545    ) {
17546        if !self.input_enabled {
17547            return;
17548        }
17549
17550        let transaction = self.transact(window, cx, |this, window, cx| {
17551            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
17552                let snapshot = this.buffer.read(cx).read(cx);
17553                if let Some(relative_range_utf16) = range_utf16.as_ref() {
17554                    for marked_range in &mut marked_ranges {
17555                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
17556                        marked_range.start.0 += relative_range_utf16.start;
17557                        marked_range.start =
17558                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
17559                        marked_range.end =
17560                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
17561                    }
17562                }
17563                Some(marked_ranges)
17564            } else if let Some(range_utf16) = range_utf16 {
17565                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
17566                Some(this.selection_replacement_ranges(range_utf16, cx))
17567            } else {
17568                None
17569            };
17570
17571            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
17572                let newest_selection_id = this.selections.newest_anchor().id;
17573                this.selections
17574                    .all::<OffsetUtf16>(cx)
17575                    .iter()
17576                    .zip(ranges_to_replace.iter())
17577                    .find_map(|(selection, range)| {
17578                        if selection.id == newest_selection_id {
17579                            Some(
17580                                (range.start.0 as isize - selection.head().0 as isize)
17581                                    ..(range.end.0 as isize - selection.head().0 as isize),
17582                            )
17583                        } else {
17584                            None
17585                        }
17586                    })
17587            });
17588
17589            cx.emit(EditorEvent::InputHandled {
17590                utf16_range_to_replace: range_to_replace,
17591                text: text.into(),
17592            });
17593
17594            if let Some(ranges) = ranges_to_replace {
17595                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
17596            }
17597
17598            let marked_ranges = {
17599                let snapshot = this.buffer.read(cx).read(cx);
17600                this.selections
17601                    .disjoint_anchors()
17602                    .iter()
17603                    .map(|selection| {
17604                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
17605                    })
17606                    .collect::<Vec<_>>()
17607            };
17608
17609            if text.is_empty() {
17610                this.unmark_text(window, cx);
17611            } else {
17612                this.highlight_text::<InputComposition>(
17613                    marked_ranges.clone(),
17614                    HighlightStyle {
17615                        underline: Some(UnderlineStyle {
17616                            thickness: px(1.),
17617                            color: None,
17618                            wavy: false,
17619                        }),
17620                        ..Default::default()
17621                    },
17622                    cx,
17623                );
17624            }
17625
17626            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
17627            let use_autoclose = this.use_autoclose;
17628            let use_auto_surround = this.use_auto_surround;
17629            this.set_use_autoclose(false);
17630            this.set_use_auto_surround(false);
17631            this.handle_input(text, window, cx);
17632            this.set_use_autoclose(use_autoclose);
17633            this.set_use_auto_surround(use_auto_surround);
17634
17635            if let Some(new_selected_range) = new_selected_range_utf16 {
17636                let snapshot = this.buffer.read(cx).read(cx);
17637                let new_selected_ranges = marked_ranges
17638                    .into_iter()
17639                    .map(|marked_range| {
17640                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
17641                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
17642                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
17643                        snapshot.clip_offset_utf16(new_start, Bias::Left)
17644                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
17645                    })
17646                    .collect::<Vec<_>>();
17647
17648                drop(snapshot);
17649                this.change_selections(None, window, cx, |selections| {
17650                    selections.select_ranges(new_selected_ranges)
17651                });
17652            }
17653        });
17654
17655        self.ime_transaction = self.ime_transaction.or(transaction);
17656        if let Some(transaction) = self.ime_transaction {
17657            self.buffer.update(cx, |buffer, cx| {
17658                buffer.group_until_transaction(transaction, cx);
17659            });
17660        }
17661
17662        if self.text_highlights::<InputComposition>(cx).is_none() {
17663            self.ime_transaction.take();
17664        }
17665    }
17666
17667    fn bounds_for_range(
17668        &mut self,
17669        range_utf16: Range<usize>,
17670        element_bounds: gpui::Bounds<Pixels>,
17671        window: &mut Window,
17672        cx: &mut Context<Self>,
17673    ) -> Option<gpui::Bounds<Pixels>> {
17674        let text_layout_details = self.text_layout_details(window);
17675        let gpui::Size {
17676            width: em_width,
17677            height: line_height,
17678        } = self.character_size(window);
17679
17680        let snapshot = self.snapshot(window, cx);
17681        let scroll_position = snapshot.scroll_position();
17682        let scroll_left = scroll_position.x * em_width;
17683
17684        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
17685        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
17686            + self.gutter_dimensions.width
17687            + self.gutter_dimensions.margin;
17688        let y = line_height * (start.row().as_f32() - scroll_position.y);
17689
17690        Some(Bounds {
17691            origin: element_bounds.origin + point(x, y),
17692            size: size(em_width, line_height),
17693        })
17694    }
17695
17696    fn character_index_for_point(
17697        &mut self,
17698        point: gpui::Point<Pixels>,
17699        _window: &mut Window,
17700        _cx: &mut Context<Self>,
17701    ) -> Option<usize> {
17702        let position_map = self.last_position_map.as_ref()?;
17703        if !position_map.text_hitbox.contains(&point) {
17704            return None;
17705        }
17706        let display_point = position_map.point_for_position(point).previous_valid;
17707        let anchor = position_map
17708            .snapshot
17709            .display_point_to_anchor(display_point, Bias::Left);
17710        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
17711        Some(utf16_offset.0)
17712    }
17713}
17714
17715trait SelectionExt {
17716    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
17717    fn spanned_rows(
17718        &self,
17719        include_end_if_at_line_start: bool,
17720        map: &DisplaySnapshot,
17721    ) -> Range<MultiBufferRow>;
17722}
17723
17724impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
17725    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
17726        let start = self
17727            .start
17728            .to_point(&map.buffer_snapshot)
17729            .to_display_point(map);
17730        let end = self
17731            .end
17732            .to_point(&map.buffer_snapshot)
17733            .to_display_point(map);
17734        if self.reversed {
17735            end..start
17736        } else {
17737            start..end
17738        }
17739    }
17740
17741    fn spanned_rows(
17742        &self,
17743        include_end_if_at_line_start: bool,
17744        map: &DisplaySnapshot,
17745    ) -> Range<MultiBufferRow> {
17746        let start = self.start.to_point(&map.buffer_snapshot);
17747        let mut end = self.end.to_point(&map.buffer_snapshot);
17748        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
17749            end.row -= 1;
17750        }
17751
17752        let buffer_start = map.prev_line_boundary(start).0;
17753        let buffer_end = map.next_line_boundary(end).0;
17754        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
17755    }
17756}
17757
17758impl<T: InvalidationRegion> InvalidationStack<T> {
17759    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
17760    where
17761        S: Clone + ToOffset,
17762    {
17763        while let Some(region) = self.last() {
17764            let all_selections_inside_invalidation_ranges =
17765                if selections.len() == region.ranges().len() {
17766                    selections
17767                        .iter()
17768                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
17769                        .all(|(selection, invalidation_range)| {
17770                            let head = selection.head().to_offset(buffer);
17771                            invalidation_range.start <= head && invalidation_range.end >= head
17772                        })
17773                } else {
17774                    false
17775                };
17776
17777            if all_selections_inside_invalidation_ranges {
17778                break;
17779            } else {
17780                self.pop();
17781            }
17782        }
17783    }
17784}
17785
17786impl<T> Default for InvalidationStack<T> {
17787    fn default() -> Self {
17788        Self(Default::default())
17789    }
17790}
17791
17792impl<T> Deref for InvalidationStack<T> {
17793    type Target = Vec<T>;
17794
17795    fn deref(&self) -> &Self::Target {
17796        &self.0
17797    }
17798}
17799
17800impl<T> DerefMut for InvalidationStack<T> {
17801    fn deref_mut(&mut self) -> &mut Self::Target {
17802        &mut self.0
17803    }
17804}
17805
17806impl InvalidationRegion for SnippetState {
17807    fn ranges(&self) -> &[Range<Anchor>] {
17808        &self.ranges[self.active_index]
17809    }
17810}
17811
17812pub fn diagnostic_block_renderer(
17813    diagnostic: Diagnostic,
17814    max_message_rows: Option<u8>,
17815    allow_closing: bool,
17816) -> RenderBlock {
17817    let (text_without_backticks, code_ranges) =
17818        highlight_diagnostic_message(&diagnostic, max_message_rows);
17819
17820    Arc::new(move |cx: &mut BlockContext| {
17821        let group_id: SharedString = cx.block_id.to_string().into();
17822
17823        let mut text_style = cx.window.text_style().clone();
17824        text_style.color = diagnostic_style(diagnostic.severity, cx.theme().status());
17825        let theme_settings = ThemeSettings::get_global(cx);
17826        text_style.font_family = theme_settings.buffer_font.family.clone();
17827        text_style.font_style = theme_settings.buffer_font.style;
17828        text_style.font_features = theme_settings.buffer_font.features.clone();
17829        text_style.font_weight = theme_settings.buffer_font.weight;
17830
17831        let multi_line_diagnostic = diagnostic.message.contains('\n');
17832
17833        let buttons = |diagnostic: &Diagnostic| {
17834            if multi_line_diagnostic {
17835                v_flex()
17836            } else {
17837                h_flex()
17838            }
17839            .when(allow_closing, |div| {
17840                div.children(diagnostic.is_primary.then(|| {
17841                    IconButton::new("close-block", IconName::XCircle)
17842                        .icon_color(Color::Muted)
17843                        .size(ButtonSize::Compact)
17844                        .style(ButtonStyle::Transparent)
17845                        .visible_on_hover(group_id.clone())
17846                        .on_click(move |_click, window, cx| {
17847                            window.dispatch_action(Box::new(Cancel), cx)
17848                        })
17849                        .tooltip(|window, cx| {
17850                            Tooltip::for_action("Close Diagnostics", &Cancel, window, cx)
17851                        })
17852                }))
17853            })
17854            .child(
17855                IconButton::new("copy-block", IconName::Copy)
17856                    .icon_color(Color::Muted)
17857                    .size(ButtonSize::Compact)
17858                    .style(ButtonStyle::Transparent)
17859                    .visible_on_hover(group_id.clone())
17860                    .on_click({
17861                        let message = diagnostic.message.clone();
17862                        move |_click, _, cx| {
17863                            cx.write_to_clipboard(ClipboardItem::new_string(message.clone()))
17864                        }
17865                    })
17866                    .tooltip(Tooltip::text("Copy diagnostic message")),
17867            )
17868        };
17869
17870        let icon_size = buttons(&diagnostic).into_any_element().layout_as_root(
17871            AvailableSpace::min_size(),
17872            cx.window,
17873            cx.app,
17874        );
17875
17876        h_flex()
17877            .id(cx.block_id)
17878            .group(group_id.clone())
17879            .relative()
17880            .size_full()
17881            .block_mouse_down()
17882            .pl(cx.gutter_dimensions.width)
17883            .w(cx.max_width - cx.gutter_dimensions.full_width())
17884            .child(
17885                div()
17886                    .flex()
17887                    .w(cx.anchor_x - cx.gutter_dimensions.width - icon_size.width)
17888                    .flex_shrink(),
17889            )
17890            .child(buttons(&diagnostic))
17891            .child(div().flex().flex_shrink_0().child(
17892                StyledText::new(text_without_backticks.clone()).with_highlights(
17893                    &text_style,
17894                    code_ranges.iter().map(|range| {
17895                        (
17896                            range.clone(),
17897                            HighlightStyle {
17898                                font_weight: Some(FontWeight::BOLD),
17899                                ..Default::default()
17900                            },
17901                        )
17902                    }),
17903                ),
17904            ))
17905            .into_any_element()
17906    })
17907}
17908
17909fn inline_completion_edit_text(
17910    current_snapshot: &BufferSnapshot,
17911    edits: &[(Range<Anchor>, String)],
17912    edit_preview: &EditPreview,
17913    include_deletions: bool,
17914    cx: &App,
17915) -> HighlightedText {
17916    let edits = edits
17917        .iter()
17918        .map(|(anchor, text)| {
17919            (
17920                anchor.start.text_anchor..anchor.end.text_anchor,
17921                text.clone(),
17922            )
17923        })
17924        .collect::<Vec<_>>();
17925
17926    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
17927}
17928
17929pub fn highlight_diagnostic_message(
17930    diagnostic: &Diagnostic,
17931    mut max_message_rows: Option<u8>,
17932) -> (SharedString, Vec<Range<usize>>) {
17933    let mut text_without_backticks = String::new();
17934    let mut code_ranges = Vec::new();
17935
17936    if let Some(source) = &diagnostic.source {
17937        text_without_backticks.push_str(source);
17938        code_ranges.push(0..source.len());
17939        text_without_backticks.push_str(": ");
17940    }
17941
17942    let mut prev_offset = 0;
17943    let mut in_code_block = false;
17944    let has_row_limit = max_message_rows.is_some();
17945    let mut newline_indices = diagnostic
17946        .message
17947        .match_indices('\n')
17948        .filter(|_| has_row_limit)
17949        .map(|(ix, _)| ix)
17950        .fuse()
17951        .peekable();
17952
17953    for (quote_ix, _) in diagnostic
17954        .message
17955        .match_indices('`')
17956        .chain([(diagnostic.message.len(), "")])
17957    {
17958        let mut first_newline_ix = None;
17959        let mut last_newline_ix = None;
17960        while let Some(newline_ix) = newline_indices.peek() {
17961            if *newline_ix < quote_ix {
17962                if first_newline_ix.is_none() {
17963                    first_newline_ix = Some(*newline_ix);
17964                }
17965                last_newline_ix = Some(*newline_ix);
17966
17967                if let Some(rows_left) = &mut max_message_rows {
17968                    if *rows_left == 0 {
17969                        break;
17970                    } else {
17971                        *rows_left -= 1;
17972                    }
17973                }
17974                let _ = newline_indices.next();
17975            } else {
17976                break;
17977            }
17978        }
17979        let prev_len = text_without_backticks.len();
17980        let new_text = &diagnostic.message[prev_offset..first_newline_ix.unwrap_or(quote_ix)];
17981        text_without_backticks.push_str(new_text);
17982        if in_code_block {
17983            code_ranges.push(prev_len..text_without_backticks.len());
17984        }
17985        prev_offset = last_newline_ix.unwrap_or(quote_ix) + 1;
17986        in_code_block = !in_code_block;
17987        if first_newline_ix.map_or(false, |newline_ix| newline_ix < quote_ix) {
17988            text_without_backticks.push_str("...");
17989            break;
17990        }
17991    }
17992
17993    (text_without_backticks.into(), code_ranges)
17994}
17995
17996fn diagnostic_style(severity: DiagnosticSeverity, colors: &StatusColors) -> Hsla {
17997    match severity {
17998        DiagnosticSeverity::ERROR => colors.error,
17999        DiagnosticSeverity::WARNING => colors.warning,
18000        DiagnosticSeverity::INFORMATION => colors.info,
18001        DiagnosticSeverity::HINT => colors.info,
18002        _ => colors.ignored,
18003    }
18004}
18005
18006pub fn styled_runs_for_code_label<'a>(
18007    label: &'a CodeLabel,
18008    syntax_theme: &'a theme::SyntaxTheme,
18009) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
18010    let fade_out = HighlightStyle {
18011        fade_out: Some(0.35),
18012        ..Default::default()
18013    };
18014
18015    let mut prev_end = label.filter_range.end;
18016    label
18017        .runs
18018        .iter()
18019        .enumerate()
18020        .flat_map(move |(ix, (range, highlight_id))| {
18021            let style = if let Some(style) = highlight_id.style(syntax_theme) {
18022                style
18023            } else {
18024                return Default::default();
18025            };
18026            let mut muted_style = style;
18027            muted_style.highlight(fade_out);
18028
18029            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
18030            if range.start >= label.filter_range.end {
18031                if range.start > prev_end {
18032                    runs.push((prev_end..range.start, fade_out));
18033                }
18034                runs.push((range.clone(), muted_style));
18035            } else if range.end <= label.filter_range.end {
18036                runs.push((range.clone(), style));
18037            } else {
18038                runs.push((range.start..label.filter_range.end, style));
18039                runs.push((label.filter_range.end..range.end, muted_style));
18040            }
18041            prev_end = cmp::max(prev_end, range.end);
18042
18043            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
18044                runs.push((prev_end..label.text.len(), fade_out));
18045            }
18046
18047            runs
18048        })
18049}
18050
18051pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
18052    let mut prev_index = 0;
18053    let mut prev_codepoint: Option<char> = None;
18054    text.char_indices()
18055        .chain([(text.len(), '\0')])
18056        .filter_map(move |(index, codepoint)| {
18057            let prev_codepoint = prev_codepoint.replace(codepoint)?;
18058            let is_boundary = index == text.len()
18059                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
18060                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
18061            if is_boundary {
18062                let chunk = &text[prev_index..index];
18063                prev_index = index;
18064                Some(chunk)
18065            } else {
18066                None
18067            }
18068        })
18069}
18070
18071pub trait RangeToAnchorExt: Sized {
18072    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
18073
18074    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
18075        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
18076        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
18077    }
18078}
18079
18080impl<T: ToOffset> RangeToAnchorExt for Range<T> {
18081    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
18082        let start_offset = self.start.to_offset(snapshot);
18083        let end_offset = self.end.to_offset(snapshot);
18084        if start_offset == end_offset {
18085            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
18086        } else {
18087            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
18088        }
18089    }
18090}
18091
18092pub trait RowExt {
18093    fn as_f32(&self) -> f32;
18094
18095    fn next_row(&self) -> Self;
18096
18097    fn previous_row(&self) -> Self;
18098
18099    fn minus(&self, other: Self) -> u32;
18100}
18101
18102impl RowExt for DisplayRow {
18103    fn as_f32(&self) -> f32 {
18104        self.0 as f32
18105    }
18106
18107    fn next_row(&self) -> Self {
18108        Self(self.0 + 1)
18109    }
18110
18111    fn previous_row(&self) -> Self {
18112        Self(self.0.saturating_sub(1))
18113    }
18114
18115    fn minus(&self, other: Self) -> u32 {
18116        self.0 - other.0
18117    }
18118}
18119
18120impl RowExt for MultiBufferRow {
18121    fn as_f32(&self) -> f32 {
18122        self.0 as f32
18123    }
18124
18125    fn next_row(&self) -> Self {
18126        Self(self.0 + 1)
18127    }
18128
18129    fn previous_row(&self) -> Self {
18130        Self(self.0.saturating_sub(1))
18131    }
18132
18133    fn minus(&self, other: Self) -> u32 {
18134        self.0 - other.0
18135    }
18136}
18137
18138trait RowRangeExt {
18139    type Row;
18140
18141    fn len(&self) -> usize;
18142
18143    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
18144}
18145
18146impl RowRangeExt for Range<MultiBufferRow> {
18147    type Row = MultiBufferRow;
18148
18149    fn len(&self) -> usize {
18150        (self.end.0 - self.start.0) as usize
18151    }
18152
18153    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
18154        (self.start.0..self.end.0).map(MultiBufferRow)
18155    }
18156}
18157
18158impl RowRangeExt for Range<DisplayRow> {
18159    type Row = DisplayRow;
18160
18161    fn len(&self) -> usize {
18162        (self.end.0 - self.start.0) as usize
18163    }
18164
18165    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
18166        (self.start.0..self.end.0).map(DisplayRow)
18167    }
18168}
18169
18170/// If select range has more than one line, we
18171/// just point the cursor to range.start.
18172fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
18173    if range.start.row == range.end.row {
18174        range
18175    } else {
18176        range.start..range.start
18177    }
18178}
18179pub struct KillRing(ClipboardItem);
18180impl Global for KillRing {}
18181
18182const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
18183
18184fn all_edits_insertions_or_deletions(
18185    edits: &Vec<(Range<Anchor>, String)>,
18186    snapshot: &MultiBufferSnapshot,
18187) -> bool {
18188    let mut all_insertions = true;
18189    let mut all_deletions = true;
18190
18191    for (range, new_text) in edits.iter() {
18192        let range_is_empty = range.to_offset(&snapshot).is_empty();
18193        let text_is_empty = new_text.is_empty();
18194
18195        if range_is_empty != text_is_empty {
18196            if range_is_empty {
18197                all_deletions = false;
18198            } else {
18199                all_insertions = false;
18200            }
18201        } else {
18202            return false;
18203        }
18204
18205        if !all_insertions && !all_deletions {
18206            return false;
18207        }
18208    }
18209    all_insertions || all_deletions
18210}