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 it's behaviour.
   15pub mod actions;
   16mod blink_manager;
   17pub mod display_map;
   18mod editor_settings;
   19mod element;
   20mod inlay_hint_cache;
   21
   22mod debounced_delay;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26mod hover_popover;
   27pub mod items;
   28mod mouse_context_menu;
   29pub mod movement;
   30mod persistence;
   31mod rust_analyzer_ext;
   32pub mod scroll;
   33mod selections_collection;
   34
   35#[cfg(test)]
   36mod editor_tests;
   37#[cfg(any(test, feature = "test-support"))]
   38pub mod test;
   39use ::git::diff::DiffHunk;
   40pub(crate) use actions::*;
   41use aho_corasick::AhoCorasick;
   42use anyhow::{anyhow, Context as _, Result};
   43use blink_manager::BlinkManager;
   44use client::{Collaborator, ParticipantIndex};
   45use clock::ReplicaId;
   46use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
   47use convert_case::{Case, Casing};
   48use copilot::Copilot;
   49use debounced_delay::DebouncedDelay;
   50pub use display_map::DisplayPoint;
   51use display_map::*;
   52pub use editor_settings::EditorSettings;
   53use element::LineWithInvisibles;
   54pub use element::{Cursor, EditorElement, HighlightedRange, HighlightedRangeLine};
   55use futures::FutureExt;
   56use fuzzy::{StringMatch, StringMatchCandidate};
   57use git::diff_hunk_to_display;
   58use gpui::{
   59    div, impl_actions, point, prelude::*, px, relative, rems, size, uniform_list, Action,
   60    AnyElement, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Context,
   61    DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusableView, FontId, FontStyle,
   62    FontWeight, HighlightStyle, Hsla, InteractiveText, KeyContext, Model, MouseButton,
   63    ParentElement, Pixels, Render, SharedString, Styled, StyledText, Subscription, Task, TextStyle,
   64    UnderlineStyle, UniformListScrollHandle, View, ViewContext, ViewInputHandler, VisualContext,
   65    WeakView, WhiteSpace, WindowContext,
   66};
   67use highlight_matching_bracket::refresh_matching_bracket_highlights;
   68use hover_popover::{hide_hover, HoverState};
   69use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
   70pub use items::MAX_TAB_TITLE_LEN;
   71use itertools::Itertools;
   72use language::{char_kind, CharKind};
   73use language::{
   74    language_settings::{self, all_language_settings, InlayHintSettings},
   75    markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CodeAction,
   76    CodeLabel, Completion, CursorShape, Diagnostic, Documentation, IndentKind, IndentSize,
   77    Language, OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId,
   78};
   79
   80use hover_links::{HoverLink, HoveredLinkState, InlayHighlight};
   81use lsp::{DiagnosticSeverity, LanguageServerId};
   82use mouse_context_menu::MouseContextMenu;
   83use movement::TextLayoutDetails;
   84use multi_buffer::ToOffsetUtf16;
   85pub use multi_buffer::{
   86    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
   87    ToPoint,
   88};
   89use ordered_float::OrderedFloat;
   90use parking_lot::{Mutex, RwLock};
   91use project::{FormatTrigger, Location, Project, ProjectPath, ProjectTransaction};
   92use rand::prelude::*;
   93use rpc::proto::*;
   94use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
   95use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
   96use serde::{Deserialize, Serialize};
   97use settings::{Settings, SettingsStore};
   98use smallvec::SmallVec;
   99use snippet::Snippet;
  100use std::{
  101    any::TypeId,
  102    borrow::Cow,
  103    cmp::{self, Ordering, Reverse},
  104    mem,
  105    num::NonZeroU32,
  106    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  107    path::Path,
  108    sync::Arc,
  109    time::{Duration, Instant},
  110};
  111pub use sum_tree::Bias;
  112use sum_tree::TreeMap;
  113use text::{BufferId, OffsetUtf16, Rope};
  114use theme::{
  115    observe_buffer_font_size_adjustment, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme,
  116    ThemeColors, ThemeSettings,
  117};
  118use ui::{
  119    h_flex, prelude::*, ButtonSize, ButtonStyle, IconButton, IconName, IconSize, ListItem, Popover,
  120    Tooltip,
  121};
  122use util::{maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
  123use workspace::Toast;
  124use workspace::{searchable::SearchEvent, ItemNavHistory, Pane, SplitDirection, ViewId, Workspace};
  125
  126use crate::hover_links::find_url;
  127
  128const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  129const MAX_LINE_LEN: usize = 1024;
  130const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  131const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  132const COPILOT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
  133pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  134#[doc(hidden)]
  135pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  136#[doc(hidden)]
  137pub const DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
  138
  139pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
  140
  141pub fn render_parsed_markdown(
  142    element_id: impl Into<ElementId>,
  143    parsed: &language::ParsedMarkdown,
  144    editor_style: &EditorStyle,
  145    workspace: Option<WeakView<Workspace>>,
  146    cx: &mut ViewContext<Editor>,
  147) -> InteractiveText {
  148    let code_span_background_color = cx
  149        .theme()
  150        .colors()
  151        .editor_document_highlight_read_background;
  152
  153    let highlights = gpui::combine_highlights(
  154        parsed.highlights.iter().filter_map(|(range, highlight)| {
  155            let highlight = highlight.to_highlight_style(&editor_style.syntax)?;
  156            Some((range.clone(), highlight))
  157        }),
  158        parsed
  159            .regions
  160            .iter()
  161            .zip(&parsed.region_ranges)
  162            .filter_map(|(region, range)| {
  163                if region.code {
  164                    Some((
  165                        range.clone(),
  166                        HighlightStyle {
  167                            background_color: Some(code_span_background_color),
  168                            ..Default::default()
  169                        },
  170                    ))
  171                } else {
  172                    None
  173                }
  174            }),
  175    );
  176
  177    let mut links = Vec::new();
  178    let mut link_ranges = Vec::new();
  179    for (range, region) in parsed.region_ranges.iter().zip(&parsed.regions) {
  180        if let Some(link) = region.link.clone() {
  181            links.push(link);
  182            link_ranges.push(range.clone());
  183        }
  184    }
  185
  186    InteractiveText::new(
  187        element_id,
  188        StyledText::new(parsed.text.clone()).with_highlights(&editor_style.text, highlights),
  189    )
  190    .on_click(link_ranges, move |clicked_range_ix, cx| {
  191        match &links[clicked_range_ix] {
  192            markdown::Link::Web { url } => cx.open_url(url),
  193            markdown::Link::Path { path } => {
  194                if let Some(workspace) = &workspace {
  195                    _ = workspace.update(cx, |workspace, cx| {
  196                        workspace.open_abs_path(path.clone(), false, cx).detach();
  197                    });
  198                }
  199            }
  200        }
  201    })
  202}
  203
  204#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  205pub(crate) enum InlayId {
  206    Suggestion(usize),
  207    Hint(usize),
  208}
  209
  210impl InlayId {
  211    fn id(&self) -> usize {
  212        match self {
  213            Self::Suggestion(id) => *id,
  214            Self::Hint(id) => *id,
  215        }
  216    }
  217}
  218
  219enum DocumentHighlightRead {}
  220enum DocumentHighlightWrite {}
  221enum InputComposition {}
  222
  223#[derive(Copy, Clone, PartialEq, Eq)]
  224pub enum Direction {
  225    Prev,
  226    Next,
  227}
  228
  229pub fn init_settings(cx: &mut AppContext) {
  230    EditorSettings::register(cx);
  231}
  232
  233pub fn init(cx: &mut AppContext) {
  234    init_settings(cx);
  235
  236    workspace::register_project_item::<Editor>(cx);
  237    workspace::register_followable_item::<Editor>(cx);
  238    workspace::register_deserializable_item::<Editor>(cx);
  239    cx.observe_new_views(
  240        |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
  241            workspace.register_action(Editor::new_file);
  242            workspace.register_action(Editor::new_file_in_direction);
  243        },
  244    )
  245    .detach();
  246
  247    cx.on_action(move |_: &workspace::NewFile, cx| {
  248        let app_state = workspace::AppState::global(cx);
  249        if let Some(app_state) = app_state.upgrade() {
  250            workspace::open_new(&app_state, cx, |workspace, cx| {
  251                Editor::new_file(workspace, &Default::default(), cx)
  252            })
  253            .detach();
  254        }
  255    });
  256    cx.on_action(move |_: &workspace::NewWindow, cx| {
  257        let app_state = workspace::AppState::global(cx);
  258        if let Some(app_state) = app_state.upgrade() {
  259            workspace::open_new(&app_state, cx, |workspace, cx| {
  260                Editor::new_file(workspace, &Default::default(), cx)
  261            })
  262            .detach();
  263        }
  264    });
  265}
  266
  267trait InvalidationRegion {
  268    fn ranges(&self) -> &[Range<Anchor>];
  269}
  270
  271#[derive(Clone, Debug, PartialEq)]
  272pub enum SelectPhase {
  273    Begin {
  274        position: DisplayPoint,
  275        add: bool,
  276        click_count: usize,
  277    },
  278    BeginColumnar {
  279        position: DisplayPoint,
  280        goal_column: u32,
  281    },
  282    Extend {
  283        position: DisplayPoint,
  284        click_count: usize,
  285    },
  286    Update {
  287        position: DisplayPoint,
  288        goal_column: u32,
  289        scroll_delta: gpui::Point<f32>,
  290    },
  291    End,
  292}
  293
  294#[derive(Clone, Debug)]
  295pub enum SelectMode {
  296    Character,
  297    Word(Range<Anchor>),
  298    Line(Range<Anchor>),
  299    All,
  300}
  301
  302#[derive(Copy, Clone, PartialEq, Eq, Debug)]
  303pub enum EditorMode {
  304    SingleLine,
  305    AutoHeight { max_lines: usize },
  306    Full,
  307}
  308
  309#[derive(Clone, Debug)]
  310pub enum SoftWrap {
  311    None,
  312    EditorWidth,
  313    Column(u32),
  314}
  315
  316#[derive(Clone)]
  317pub struct EditorStyle {
  318    pub background: Hsla,
  319    pub local_player: PlayerColor,
  320    pub text: TextStyle,
  321    pub scrollbar_width: Pixels,
  322    pub syntax: Arc<SyntaxTheme>,
  323    pub status: StatusColors,
  324    pub inlays_style: HighlightStyle,
  325    pub suggestions_style: HighlightStyle,
  326}
  327
  328impl Default for EditorStyle {
  329    fn default() -> Self {
  330        Self {
  331            background: Hsla::default(),
  332            local_player: PlayerColor::default(),
  333            text: TextStyle::default(),
  334            scrollbar_width: Pixels::default(),
  335            syntax: Default::default(),
  336            // HACK: Status colors don't have a real default.
  337            // We should look into removing the status colors from the editor
  338            // style and retrieve them directly from the theme.
  339            status: StatusColors::dark(),
  340            inlays_style: HighlightStyle::default(),
  341            suggestions_style: HighlightStyle::default(),
  342        }
  343    }
  344}
  345
  346type CompletionId = usize;
  347
  348// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  349// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  350
  351type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<Range<Anchor>>);
  352type InlayBackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<InlayHighlight>);
  353
  354/// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`]
  355///
  356/// See the [module level documentation](self) for more information.
  357pub struct Editor {
  358    handle: WeakView<Self>,
  359    focus_handle: FocusHandle,
  360    /// The text buffer being edited
  361    buffer: Model<MultiBuffer>,
  362    /// Map of how text in the buffer should be displayed.
  363    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  364    display_map: Model<DisplayMap>,
  365    pub selections: SelectionsCollection,
  366    pub scroll_manager: ScrollManager,
  367    columnar_selection_tail: Option<Anchor>,
  368    add_selections_state: Option<AddSelectionsState>,
  369    select_next_state: Option<SelectNextState>,
  370    select_prev_state: Option<SelectNextState>,
  371    selection_history: SelectionHistory,
  372    autoclose_regions: Vec<AutocloseRegion>,
  373    snippet_stack: InvalidationStack<SnippetState>,
  374    select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
  375    ime_transaction: Option<TransactionId>,
  376    active_diagnostics: Option<ActiveDiagnosticGroup>,
  377    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  378    project: Option<Model<Project>>,
  379    completion_provider: Option<Box<dyn CompletionProvider>>,
  380    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  381    blink_manager: Model<BlinkManager>,
  382    show_cursor_names: bool,
  383    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  384    pub show_local_selections: bool,
  385    mode: EditorMode,
  386    show_breadcrumbs: bool,
  387    show_gutter: bool,
  388    show_wrap_guides: Option<bool>,
  389    placeholder_text: Option<Arc<str>>,
  390    highlighted_rows: Option<Range<u32>>,
  391    background_highlights: BTreeMap<TypeId, BackgroundHighlight>,
  392    inlay_background_highlights: TreeMap<Option<TypeId>, InlayBackgroundHighlight>,
  393    nav_history: Option<ItemNavHistory>,
  394    context_menu: RwLock<Option<ContextMenu>>,
  395    mouse_context_menu: Option<MouseContextMenu>,
  396    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  397    next_completion_id: CompletionId,
  398    completion_documentation_pre_resolve_debounce: DebouncedDelay,
  399    available_code_actions: Option<(Model<Buffer>, Arc<[CodeAction]>)>,
  400    code_actions_task: Option<Task<()>>,
  401    document_highlights_task: Option<Task<()>>,
  402    pending_rename: Option<RenameState>,
  403    searchable: bool,
  404    cursor_shape: CursorShape,
  405    collapse_matches: bool,
  406    autoindent_mode: Option<AutoindentMode>,
  407    workspace: Option<(WeakView<Workspace>, i64)>,
  408    keymap_context_layers: BTreeMap<TypeId, KeyContext>,
  409    input_enabled: bool,
  410    use_modal_editing: bool,
  411    read_only: bool,
  412    leader_peer_id: Option<PeerId>,
  413    remote_id: Option<ViewId>,
  414    hover_state: HoverState,
  415    gutter_hovered: bool,
  416    hovered_link_state: Option<HoveredLinkState>,
  417    copilot_state: CopilotState,
  418    inlay_hint_cache: InlayHintCache,
  419    next_inlay_id: usize,
  420    _subscriptions: Vec<Subscription>,
  421    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  422    gutter_width: Pixels,
  423    style: Option<EditorStyle>,
  424    editor_actions: Vec<Box<dyn Fn(&mut ViewContext<Self>)>>,
  425    show_copilot_suggestions: bool,
  426    use_autoclose: bool,
  427    custom_context_menu: Option<
  428        Box<
  429            dyn 'static
  430                + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,
  431        >,
  432    >,
  433}
  434
  435pub struct EditorSnapshot {
  436    pub mode: EditorMode,
  437    show_gutter: bool,
  438    pub display_snapshot: DisplaySnapshot,
  439    pub placeholder_text: Option<Arc<str>>,
  440    is_focused: bool,
  441    scroll_anchor: ScrollAnchor,
  442    ongoing_scroll: OngoingScroll,
  443}
  444
  445pub struct GutterDimensions {
  446    pub padding: Pixels,
  447    pub width: Pixels,
  448    pub margin: Pixels,
  449}
  450
  451impl Default for GutterDimensions {
  452    fn default() -> Self {
  453        Self {
  454            padding: Pixels::ZERO,
  455            width: Pixels::ZERO,
  456            margin: Pixels::ZERO,
  457        }
  458    }
  459}
  460
  461#[derive(Debug)]
  462pub struct RemoteSelection {
  463    pub replica_id: ReplicaId,
  464    pub selection: Selection<Anchor>,
  465    pub cursor_shape: CursorShape,
  466    pub peer_id: PeerId,
  467    pub line_mode: bool,
  468    pub participant_index: Option<ParticipantIndex>,
  469    pub user_name: Option<SharedString>,
  470}
  471
  472#[derive(Clone, Debug)]
  473struct SelectionHistoryEntry {
  474    selections: Arc<[Selection<Anchor>]>,
  475    select_next_state: Option<SelectNextState>,
  476    select_prev_state: Option<SelectNextState>,
  477    add_selections_state: Option<AddSelectionsState>,
  478}
  479
  480enum SelectionHistoryMode {
  481    Normal,
  482    Undoing,
  483    Redoing,
  484}
  485
  486#[derive(Clone, PartialEq, Eq, Hash)]
  487struct HoveredCursor {
  488    replica_id: u16,
  489    selection_id: usize,
  490}
  491
  492impl Default for SelectionHistoryMode {
  493    fn default() -> Self {
  494        Self::Normal
  495    }
  496}
  497
  498#[derive(Default)]
  499struct SelectionHistory {
  500    #[allow(clippy::type_complexity)]
  501    selections_by_transaction:
  502        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
  503    mode: SelectionHistoryMode,
  504    undo_stack: VecDeque<SelectionHistoryEntry>,
  505    redo_stack: VecDeque<SelectionHistoryEntry>,
  506}
  507
  508impl SelectionHistory {
  509    fn insert_transaction(
  510        &mut self,
  511        transaction_id: TransactionId,
  512        selections: Arc<[Selection<Anchor>]>,
  513    ) {
  514        self.selections_by_transaction
  515            .insert(transaction_id, (selections, None));
  516    }
  517
  518    #[allow(clippy::type_complexity)]
  519    fn transaction(
  520        &self,
  521        transaction_id: TransactionId,
  522    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  523        self.selections_by_transaction.get(&transaction_id)
  524    }
  525
  526    #[allow(clippy::type_complexity)]
  527    fn transaction_mut(
  528        &mut self,
  529        transaction_id: TransactionId,
  530    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
  531        self.selections_by_transaction.get_mut(&transaction_id)
  532    }
  533
  534    fn push(&mut self, entry: SelectionHistoryEntry) {
  535        if !entry.selections.is_empty() {
  536            match self.mode {
  537                SelectionHistoryMode::Normal => {
  538                    self.push_undo(entry);
  539                    self.redo_stack.clear();
  540                }
  541                SelectionHistoryMode::Undoing => self.push_redo(entry),
  542                SelectionHistoryMode::Redoing => self.push_undo(entry),
  543            }
  544        }
  545    }
  546
  547    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
  548        if self
  549            .undo_stack
  550            .back()
  551            .map_or(true, |e| e.selections != entry.selections)
  552        {
  553            self.undo_stack.push_back(entry);
  554            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  555                self.undo_stack.pop_front();
  556            }
  557        }
  558    }
  559
  560    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
  561        if self
  562            .redo_stack
  563            .back()
  564            .map_or(true, |e| e.selections != entry.selections)
  565        {
  566            self.redo_stack.push_back(entry);
  567            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
  568                self.redo_stack.pop_front();
  569            }
  570        }
  571    }
  572}
  573
  574#[derive(Clone, Debug)]
  575struct AddSelectionsState {
  576    above: bool,
  577    stack: Vec<usize>,
  578}
  579
  580#[derive(Clone)]
  581struct SelectNextState {
  582    query: AhoCorasick,
  583    wordwise: bool,
  584    done: bool,
  585}
  586
  587impl std::fmt::Debug for SelectNextState {
  588    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  589        f.debug_struct(std::any::type_name::<Self>())
  590            .field("wordwise", &self.wordwise)
  591            .field("done", &self.done)
  592            .finish()
  593    }
  594}
  595
  596#[derive(Debug)]
  597struct AutocloseRegion {
  598    selection_id: usize,
  599    range: Range<Anchor>,
  600    pair: BracketPair,
  601}
  602
  603#[derive(Debug)]
  604struct SnippetState {
  605    ranges: Vec<Vec<Range<Anchor>>>,
  606    active_index: usize,
  607}
  608
  609#[doc(hidden)]
  610pub struct RenameState {
  611    pub range: Range<Anchor>,
  612    pub old_name: Arc<str>,
  613    pub editor: View<Editor>,
  614    block_id: BlockId,
  615}
  616
  617struct InvalidationStack<T>(Vec<T>);
  618
  619enum ContextMenu {
  620    Completions(CompletionsMenu),
  621    CodeActions(CodeActionsMenu),
  622}
  623
  624impl ContextMenu {
  625    fn select_first(
  626        &mut self,
  627        project: Option<&Model<Project>>,
  628        cx: &mut ViewContext<Editor>,
  629    ) -> bool {
  630        if self.visible() {
  631            match self {
  632                ContextMenu::Completions(menu) => menu.select_first(project, cx),
  633                ContextMenu::CodeActions(menu) => menu.select_first(cx),
  634            }
  635            true
  636        } else {
  637            false
  638        }
  639    }
  640
  641    fn select_prev(
  642        &mut self,
  643        project: Option<&Model<Project>>,
  644        cx: &mut ViewContext<Editor>,
  645    ) -> bool {
  646        if self.visible() {
  647            match self {
  648                ContextMenu::Completions(menu) => menu.select_prev(project, cx),
  649                ContextMenu::CodeActions(menu) => menu.select_prev(cx),
  650            }
  651            true
  652        } else {
  653            false
  654        }
  655    }
  656
  657    fn select_next(
  658        &mut self,
  659        project: Option<&Model<Project>>,
  660        cx: &mut ViewContext<Editor>,
  661    ) -> bool {
  662        if self.visible() {
  663            match self {
  664                ContextMenu::Completions(menu) => menu.select_next(project, cx),
  665                ContextMenu::CodeActions(menu) => menu.select_next(cx),
  666            }
  667            true
  668        } else {
  669            false
  670        }
  671    }
  672
  673    fn select_last(
  674        &mut self,
  675        project: Option<&Model<Project>>,
  676        cx: &mut ViewContext<Editor>,
  677    ) -> bool {
  678        if self.visible() {
  679            match self {
  680                ContextMenu::Completions(menu) => menu.select_last(project, cx),
  681                ContextMenu::CodeActions(menu) => menu.select_last(cx),
  682            }
  683            true
  684        } else {
  685            false
  686        }
  687    }
  688
  689    fn visible(&self) -> bool {
  690        match self {
  691            ContextMenu::Completions(menu) => menu.visible(),
  692            ContextMenu::CodeActions(menu) => menu.visible(),
  693        }
  694    }
  695
  696    fn render(
  697        &self,
  698        cursor_position: DisplayPoint,
  699        style: &EditorStyle,
  700        max_height: Pixels,
  701        workspace: Option<WeakView<Workspace>>,
  702        cx: &mut ViewContext<Editor>,
  703    ) -> (DisplayPoint, AnyElement) {
  704        match self {
  705            ContextMenu::Completions(menu) => (
  706                cursor_position,
  707                menu.render(style, max_height, workspace, cx),
  708            ),
  709            ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, max_height, cx),
  710        }
  711    }
  712}
  713
  714#[derive(Clone)]
  715struct CompletionsMenu {
  716    id: CompletionId,
  717    initial_position: Anchor,
  718    buffer: Model<Buffer>,
  719    completions: Arc<RwLock<Box<[Completion]>>>,
  720    match_candidates: Arc<[StringMatchCandidate]>,
  721    matches: Arc<[StringMatch]>,
  722    selected_item: usize,
  723    scroll_handle: UniformListScrollHandle,
  724    selected_completion_documentation_resolve_debounce: Arc<Mutex<DebouncedDelay>>,
  725}
  726
  727impl CompletionsMenu {
  728    fn select_first(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  729        self.selected_item = 0;
  730        self.scroll_handle.scroll_to_item(self.selected_item);
  731        self.attempt_resolve_selected_completion_documentation(project, cx);
  732        cx.notify();
  733    }
  734
  735    fn select_prev(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  736        if self.selected_item > 0 {
  737            self.selected_item -= 1;
  738        } else {
  739            self.selected_item = self.matches.len() - 1;
  740        }
  741        self.scroll_handle.scroll_to_item(self.selected_item);
  742        self.attempt_resolve_selected_completion_documentation(project, cx);
  743        cx.notify();
  744    }
  745
  746    fn select_next(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  747        if self.selected_item + 1 < self.matches.len() {
  748            self.selected_item += 1;
  749        } else {
  750            self.selected_item = 0;
  751        }
  752        self.scroll_handle.scroll_to_item(self.selected_item);
  753        self.attempt_resolve_selected_completion_documentation(project, cx);
  754        cx.notify();
  755    }
  756
  757    fn select_last(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
  758        self.selected_item = self.matches.len() - 1;
  759        self.scroll_handle.scroll_to_item(self.selected_item);
  760        self.attempt_resolve_selected_completion_documentation(project, cx);
  761        cx.notify();
  762    }
  763
  764    fn pre_resolve_completion_documentation(
  765        completions: Arc<RwLock<Box<[Completion]>>>,
  766        matches: Arc<[StringMatch]>,
  767        editor: &Editor,
  768        cx: &mut ViewContext<Editor>,
  769    ) -> Task<()> {
  770        let settings = EditorSettings::get_global(cx);
  771        if !settings.show_completion_documentation {
  772            return Task::ready(());
  773        }
  774
  775        let Some(provider) = editor.completion_provider.as_ref() else {
  776            return Task::ready(());
  777        };
  778
  779        let resolve_task = provider.resolve_completions(
  780            matches.iter().map(|m| m.candidate_id).collect(),
  781            completions.clone(),
  782            cx,
  783        );
  784
  785        return cx.spawn(move |this, mut cx| async move {
  786            if let Some(true) = resolve_task.await.log_err() {
  787                this.update(&mut cx, |_, cx| cx.notify()).ok();
  788            }
  789        });
  790    }
  791
  792    fn attempt_resolve_selected_completion_documentation(
  793        &mut self,
  794        project: Option<&Model<Project>>,
  795        cx: &mut ViewContext<Editor>,
  796    ) {
  797        let settings = EditorSettings::get_global(cx);
  798        if !settings.show_completion_documentation {
  799            return;
  800        }
  801
  802        let completion_index = self.matches[self.selected_item].candidate_id;
  803        let Some(project) = project else {
  804            return;
  805        };
  806
  807        let resolve_task = project.update(cx, |project, cx| {
  808            project.resolve_completions(vec![completion_index], self.completions.clone(), cx)
  809        });
  810
  811        let delay_ms =
  812            EditorSettings::get_global(cx).completion_documentation_secondary_query_debounce;
  813        let delay = Duration::from_millis(delay_ms);
  814
  815        self.selected_completion_documentation_resolve_debounce
  816            .lock()
  817            .fire_new(delay, cx, |_, cx| {
  818                cx.spawn(move |this, mut cx| async move {
  819                    if let Some(true) = resolve_task.await.log_err() {
  820                        this.update(&mut cx, |_, cx| cx.notify()).ok();
  821                    }
  822                })
  823            });
  824    }
  825
  826    fn visible(&self) -> bool {
  827        !self.matches.is_empty()
  828    }
  829
  830    fn render(
  831        &self,
  832        style: &EditorStyle,
  833        max_height: Pixels,
  834        workspace: Option<WeakView<Workspace>>,
  835        cx: &mut ViewContext<Editor>,
  836    ) -> AnyElement {
  837        let settings = EditorSettings::get_global(cx);
  838        let show_completion_documentation = settings.show_completion_documentation;
  839
  840        let widest_completion_ix = self
  841            .matches
  842            .iter()
  843            .enumerate()
  844            .max_by_key(|(_, mat)| {
  845                let completions = self.completions.read();
  846                let completion = &completions[mat.candidate_id];
  847                let documentation = &completion.documentation;
  848
  849                let mut len = completion.label.text.chars().count();
  850                if let Some(Documentation::SingleLine(text)) = documentation {
  851                    if show_completion_documentation {
  852                        len += text.chars().count();
  853                    }
  854                }
  855
  856                len
  857            })
  858            .map(|(ix, _)| ix);
  859
  860        let completions = self.completions.clone();
  861        let matches = self.matches.clone();
  862        let selected_item = self.selected_item;
  863        let style = style.clone();
  864
  865        let multiline_docs = if show_completion_documentation {
  866            let mat = &self.matches[selected_item];
  867            let multiline_docs = match &self.completions.read()[mat.candidate_id].documentation {
  868                Some(Documentation::MultiLinePlainText(text)) => {
  869                    Some(div().child(SharedString::from(text.clone())))
  870                }
  871                Some(Documentation::MultiLineMarkdown(parsed)) if !parsed.text.is_empty() => {
  872                    Some(div().child(render_parsed_markdown(
  873                        "completions_markdown",
  874                        parsed,
  875                        &style,
  876                        workspace,
  877                        cx,
  878                    )))
  879                }
  880                _ => None,
  881            };
  882            multiline_docs.map(|div| {
  883                div.id("multiline_docs")
  884                    .max_h(max_height)
  885                    .flex_1()
  886                    .px_1p5()
  887                    .py_1()
  888                    .min_w(px(260.))
  889                    .max_w(px(640.))
  890                    .w(px(500.))
  891                    .overflow_y_scroll()
  892                    // Prevent a mouse down on documentation from being propagated to the editor,
  893                    // because that would move the cursor.
  894                    .on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation())
  895            })
  896        } else {
  897            None
  898        };
  899
  900        let list = uniform_list(
  901            cx.view().clone(),
  902            "completions",
  903            matches.len(),
  904            move |_editor, range, cx| {
  905                let start_ix = range.start;
  906                let completions_guard = completions.read();
  907
  908                matches[range]
  909                    .iter()
  910                    .enumerate()
  911                    .map(|(ix, mat)| {
  912                        let item_ix = start_ix + ix;
  913                        let candidate_id = mat.candidate_id;
  914                        let completion = &completions_guard[candidate_id];
  915
  916                        let documentation = if show_completion_documentation {
  917                            &completion.documentation
  918                        } else {
  919                            &None
  920                        };
  921
  922                        let highlights = gpui::combine_highlights(
  923                            mat.ranges().map(|range| (range, FontWeight::BOLD.into())),
  924                            styled_runs_for_code_label(&completion.label, &style.syntax).map(
  925                                |(range, mut highlight)| {
  926                                    // Ignore font weight for syntax highlighting, as we'll use it
  927                                    // for fuzzy matches.
  928                                    highlight.font_weight = None;
  929                                    (range, highlight)
  930                                },
  931                            ),
  932                        );
  933                        let completion_label = StyledText::new(completion.label.text.clone())
  934                            .with_highlights(&style.text, highlights);
  935                        let documentation_label =
  936                            if let Some(Documentation::SingleLine(text)) = documentation {
  937                                if text.trim().is_empty() {
  938                                    None
  939                                } else {
  940                                    Some(
  941                                        h_flex().ml_4().child(
  942                                            Label::new(text.clone())
  943                                                .size(LabelSize::Small)
  944                                                .color(Color::Muted),
  945                                        ),
  946                                    )
  947                                }
  948                            } else {
  949                                None
  950                            };
  951
  952                        div().min_w(px(220.)).max_w(px(540.)).child(
  953                            ListItem::new(mat.candidate_id)
  954                                .inset(true)
  955                                .selected(item_ix == selected_item)
  956                                .on_click(cx.listener(move |editor, _event, cx| {
  957                                    cx.stop_propagation();
  958                                    editor
  959                                        .confirm_completion(
  960                                            &ConfirmCompletion {
  961                                                item_ix: Some(item_ix),
  962                                            },
  963                                            cx,
  964                                        )
  965                                        .map(|task| task.detach_and_log_err(cx));
  966                                }))
  967                                .child(h_flex().overflow_hidden().child(completion_label))
  968                                .end_slot::<Div>(documentation_label),
  969                        )
  970                    })
  971                    .collect()
  972            },
  973        )
  974        .max_h(max_height)
  975        .track_scroll(self.scroll_handle.clone())
  976        .with_width_from_item(widest_completion_ix);
  977
  978        Popover::new()
  979            .child(list)
  980            .when_some(multiline_docs, |popover, multiline_docs| {
  981                popover.aside(multiline_docs)
  982            })
  983            .into_any_element()
  984    }
  985
  986    pub async fn filter(&mut self, query: Option<&str>, executor: BackgroundExecutor) {
  987        let mut matches = if let Some(query) = query {
  988            fuzzy::match_strings(
  989                &self.match_candidates,
  990                query,
  991                query.chars().any(|c| c.is_uppercase()),
  992                100,
  993                &Default::default(),
  994                executor,
  995            )
  996            .await
  997        } else {
  998            self.match_candidates
  999                .iter()
 1000                .enumerate()
 1001                .map(|(candidate_id, candidate)| StringMatch {
 1002                    candidate_id,
 1003                    score: Default::default(),
 1004                    positions: Default::default(),
 1005                    string: candidate.string.clone(),
 1006                })
 1007                .collect()
 1008        };
 1009
 1010        // Remove all candidates where the query's start does not match the start of any word in the candidate
 1011        if let Some(query) = query {
 1012            if let Some(query_start) = query.chars().next() {
 1013                matches.retain(|string_match| {
 1014                    split_words(&string_match.string).any(|word| {
 1015                        // Check that the first codepoint of the word as lowercase matches the first
 1016                        // codepoint of the query as lowercase
 1017                        word.chars()
 1018                            .flat_map(|codepoint| codepoint.to_lowercase())
 1019                            .zip(query_start.to_lowercase())
 1020                            .all(|(word_cp, query_cp)| word_cp == query_cp)
 1021                    })
 1022                });
 1023            }
 1024        }
 1025
 1026        let completions = self.completions.read();
 1027        matches.sort_unstable_by_key(|mat| {
 1028            // We do want to strike a balance here between what the language server tells us
 1029            // to sort by (the sort_text) and what are "obvious" good matches (i.e. when you type
 1030            // `Creat` and there is a local variable called `CreateComponent`).
 1031            // So what we do is: we bucket all matches into two buckets
 1032            // - Strong matches
 1033            // - Weak matches
 1034            // Strong matches are the ones with a high fuzzy-matcher score (the "obvious" matches)
 1035            // and the Weak matches are the rest.
 1036            //
 1037            // For the strong matches, we sort by the language-servers score first and for the weak
 1038            // matches, we prefer our fuzzy finder first.
 1039            //
 1040            // The thinking behind that: it's useless to take the sort_text the language-server gives
 1041            // us into account when it's obviously a bad match.
 1042
 1043            #[derive(PartialEq, Eq, PartialOrd, Ord)]
 1044            enum MatchScore<'a> {
 1045                Strong {
 1046                    sort_text: Option<&'a str>,
 1047                    score: Reverse<OrderedFloat<f64>>,
 1048                    sort_key: (usize, &'a str),
 1049                },
 1050                Weak {
 1051                    score: Reverse<OrderedFloat<f64>>,
 1052                    sort_text: Option<&'a str>,
 1053                    sort_key: (usize, &'a str),
 1054                },
 1055            }
 1056
 1057            let completion = &completions[mat.candidate_id];
 1058            let sort_key = completion.sort_key();
 1059            let sort_text = completion.lsp_completion.sort_text.as_deref();
 1060            let score = Reverse(OrderedFloat(mat.score));
 1061
 1062            if mat.score >= 0.2 {
 1063                MatchScore::Strong {
 1064                    sort_text,
 1065                    score,
 1066                    sort_key,
 1067                }
 1068            } else {
 1069                MatchScore::Weak {
 1070                    score,
 1071                    sort_text,
 1072                    sort_key,
 1073                }
 1074            }
 1075        });
 1076
 1077        for mat in &mut matches {
 1078            let completion = &completions[mat.candidate_id];
 1079            mat.string = completion.label.text.clone();
 1080            for position in &mut mat.positions {
 1081                *position += completion.label.filter_range.start;
 1082            }
 1083        }
 1084        drop(completions);
 1085
 1086        self.matches = matches.into();
 1087        self.selected_item = 0;
 1088    }
 1089}
 1090
 1091#[derive(Clone)]
 1092struct CodeActionsMenu {
 1093    actions: Arc<[CodeAction]>,
 1094    buffer: Model<Buffer>,
 1095    selected_item: usize,
 1096    scroll_handle: UniformListScrollHandle,
 1097    deployed_from_indicator: bool,
 1098}
 1099
 1100impl CodeActionsMenu {
 1101    fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
 1102        self.selected_item = 0;
 1103        self.scroll_handle.scroll_to_item(self.selected_item);
 1104        cx.notify()
 1105    }
 1106
 1107    fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
 1108        if self.selected_item > 0 {
 1109            self.selected_item -= 1;
 1110        } else {
 1111            self.selected_item = self.actions.len() - 1;
 1112        }
 1113        self.scroll_handle.scroll_to_item(self.selected_item);
 1114        cx.notify();
 1115    }
 1116
 1117    fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
 1118        if self.selected_item + 1 < self.actions.len() {
 1119            self.selected_item += 1;
 1120        } else {
 1121            self.selected_item = 0;
 1122        }
 1123        self.scroll_handle.scroll_to_item(self.selected_item);
 1124        cx.notify();
 1125    }
 1126
 1127    fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
 1128        self.selected_item = self.actions.len() - 1;
 1129        self.scroll_handle.scroll_to_item(self.selected_item);
 1130        cx.notify()
 1131    }
 1132
 1133    fn visible(&self) -> bool {
 1134        !self.actions.is_empty()
 1135    }
 1136
 1137    fn render(
 1138        &self,
 1139        mut cursor_position: DisplayPoint,
 1140        _style: &EditorStyle,
 1141        max_height: Pixels,
 1142        cx: &mut ViewContext<Editor>,
 1143    ) -> (DisplayPoint, AnyElement) {
 1144        let actions = self.actions.clone();
 1145        let selected_item = self.selected_item;
 1146
 1147        let element = uniform_list(
 1148            cx.view().clone(),
 1149            "code_actions_menu",
 1150            self.actions.len(),
 1151            move |_this, range, cx| {
 1152                actions[range.clone()]
 1153                    .iter()
 1154                    .enumerate()
 1155                    .map(|(ix, action)| {
 1156                        let item_ix = range.start + ix;
 1157                        let selected = selected_item == item_ix;
 1158                        let colors = cx.theme().colors();
 1159                        div()
 1160                            .px_2()
 1161                            .text_color(colors.text)
 1162                            .when(selected, |style| {
 1163                                style
 1164                                    .bg(colors.element_active)
 1165                                    .text_color(colors.text_accent)
 1166                            })
 1167                            .hover(|style| {
 1168                                style
 1169                                    .bg(colors.element_hover)
 1170                                    .text_color(colors.text_accent)
 1171                            })
 1172                            .on_mouse_down(
 1173                                MouseButton::Left,
 1174                                cx.listener(move |editor, _, cx| {
 1175                                    cx.stop_propagation();
 1176                                    editor
 1177                                        .confirm_code_action(
 1178                                            &ConfirmCodeAction {
 1179                                                item_ix: Some(item_ix),
 1180                                            },
 1181                                            cx,
 1182                                        )
 1183                                        .map(|task| task.detach_and_log_err(cx));
 1184                                }),
 1185                            )
 1186                            // TASK: It would be good to make lsp_action.title a SharedString to avoid allocating here.
 1187                            .child(SharedString::from(action.lsp_action.title.clone()))
 1188                    })
 1189                    .collect()
 1190            },
 1191        )
 1192        .elevation_1(cx)
 1193        .px_2()
 1194        .py_1()
 1195        .max_h(max_height)
 1196        .track_scroll(self.scroll_handle.clone())
 1197        .with_width_from_item(
 1198            self.actions
 1199                .iter()
 1200                .enumerate()
 1201                .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
 1202                .map(|(ix, _)| ix),
 1203        )
 1204        .into_any_element();
 1205
 1206        if self.deployed_from_indicator {
 1207            *cursor_position.column_mut() = 0;
 1208        }
 1209
 1210        (cursor_position, element)
 1211    }
 1212}
 1213
 1214pub(crate) struct CopilotState {
 1215    excerpt_id: Option<ExcerptId>,
 1216    pending_refresh: Task<Option<()>>,
 1217    pending_cycling_refresh: Task<Option<()>>,
 1218    cycled: bool,
 1219    completions: Vec<copilot::Completion>,
 1220    active_completion_index: usize,
 1221    suggestion: Option<Inlay>,
 1222}
 1223
 1224impl Default for CopilotState {
 1225    fn default() -> Self {
 1226        Self {
 1227            excerpt_id: None,
 1228            pending_cycling_refresh: Task::ready(Some(())),
 1229            pending_refresh: Task::ready(Some(())),
 1230            completions: Default::default(),
 1231            active_completion_index: 0,
 1232            cycled: false,
 1233            suggestion: None,
 1234        }
 1235    }
 1236}
 1237
 1238impl CopilotState {
 1239    fn active_completion(&self) -> Option<&copilot::Completion> {
 1240        self.completions.get(self.active_completion_index)
 1241    }
 1242
 1243    fn text_for_active_completion(
 1244        &self,
 1245        cursor: Anchor,
 1246        buffer: &MultiBufferSnapshot,
 1247    ) -> Option<&str> {
 1248        use language::ToOffset as _;
 1249
 1250        let completion = self.active_completion()?;
 1251        let excerpt_id = self.excerpt_id?;
 1252        let completion_buffer = buffer.buffer_for_excerpt(excerpt_id)?;
 1253        if excerpt_id != cursor.excerpt_id
 1254            || !completion.range.start.is_valid(completion_buffer)
 1255            || !completion.range.end.is_valid(completion_buffer)
 1256        {
 1257            return None;
 1258        }
 1259
 1260        let mut completion_range = completion.range.to_offset(&completion_buffer);
 1261        let prefix_len = Self::common_prefix(
 1262            completion_buffer.chars_for_range(completion_range.clone()),
 1263            completion.text.chars(),
 1264        );
 1265        completion_range.start += prefix_len;
 1266        let suffix_len = Self::common_prefix(
 1267            completion_buffer.reversed_chars_for_range(completion_range.clone()),
 1268            completion.text[prefix_len..].chars().rev(),
 1269        );
 1270        completion_range.end = completion_range.end.saturating_sub(suffix_len);
 1271
 1272        if completion_range.is_empty()
 1273            && completion_range.start == cursor.text_anchor.to_offset(&completion_buffer)
 1274        {
 1275            let completion_text = &completion.text[prefix_len..completion.text.len() - suffix_len];
 1276            if completion_text.trim().is_empty() {
 1277                None
 1278            } else {
 1279                Some(completion_text)
 1280            }
 1281        } else {
 1282            None
 1283        }
 1284    }
 1285
 1286    fn cycle_completions(&mut self, direction: Direction) {
 1287        match direction {
 1288            Direction::Prev => {
 1289                self.active_completion_index = if self.active_completion_index == 0 {
 1290                    self.completions.len().saturating_sub(1)
 1291                } else {
 1292                    self.active_completion_index - 1
 1293                };
 1294            }
 1295            Direction::Next => {
 1296                if self.completions.len() == 0 {
 1297                    self.active_completion_index = 0
 1298                } else {
 1299                    self.active_completion_index =
 1300                        (self.active_completion_index + 1) % self.completions.len();
 1301                }
 1302            }
 1303        }
 1304    }
 1305
 1306    fn push_completion(&mut self, new_completion: copilot::Completion) {
 1307        for completion in &self.completions {
 1308            if completion.text == new_completion.text && completion.range == new_completion.range {
 1309                return;
 1310            }
 1311        }
 1312        self.completions.push(new_completion);
 1313    }
 1314
 1315    fn common_prefix<T1: Iterator<Item = char>, T2: Iterator<Item = char>>(a: T1, b: T2) -> usize {
 1316        a.zip(b)
 1317            .take_while(|(a, b)| a == b)
 1318            .map(|(a, _)| a.len_utf8())
 1319            .sum()
 1320    }
 1321}
 1322
 1323#[derive(Debug)]
 1324struct ActiveDiagnosticGroup {
 1325    primary_range: Range<Anchor>,
 1326    primary_message: String,
 1327    blocks: HashMap<BlockId, Diagnostic>,
 1328    is_valid: bool,
 1329}
 1330
 1331#[derive(Serialize, Deserialize)]
 1332pub struct ClipboardSelection {
 1333    pub len: usize,
 1334    pub is_entire_line: bool,
 1335    pub first_line_indent: u32,
 1336}
 1337
 1338#[derive(Debug)]
 1339pub(crate) struct NavigationData {
 1340    cursor_anchor: Anchor,
 1341    cursor_position: Point,
 1342    scroll_anchor: ScrollAnchor,
 1343    scroll_top_row: u32,
 1344}
 1345
 1346enum GotoDefinitionKind {
 1347    Symbol,
 1348    Type,
 1349}
 1350
 1351#[derive(Debug, Clone)]
 1352enum InlayHintRefreshReason {
 1353    Toggle(bool),
 1354    SettingsChange(InlayHintSettings),
 1355    NewLinesShown,
 1356    BufferEdited(HashSet<Arc<Language>>),
 1357    RefreshRequested,
 1358    ExcerptsRemoved(Vec<ExcerptId>),
 1359}
 1360impl InlayHintRefreshReason {
 1361    fn description(&self) -> &'static str {
 1362        match self {
 1363            Self::Toggle(_) => "toggle",
 1364            Self::SettingsChange(_) => "settings change",
 1365            Self::NewLinesShown => "new lines shown",
 1366            Self::BufferEdited(_) => "buffer edited",
 1367            Self::RefreshRequested => "refresh requested",
 1368            Self::ExcerptsRemoved(_) => "excerpts removed",
 1369        }
 1370    }
 1371}
 1372
 1373impl Editor {
 1374    pub fn single_line(cx: &mut ViewContext<Self>) -> Self {
 1375        let buffer = cx.new_model(|cx| {
 1376            Buffer::new(
 1377                0,
 1378                BufferId::new(cx.entity_id().as_u64()).unwrap(),
 1379                String::new(),
 1380            )
 1381        });
 1382        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1383        Self::new(EditorMode::SingleLine, buffer, None, cx)
 1384    }
 1385
 1386    pub fn multi_line(cx: &mut ViewContext<Self>) -> Self {
 1387        let buffer = cx.new_model(|cx| {
 1388            Buffer::new(
 1389                0,
 1390                BufferId::new(cx.entity_id().as_u64()).unwrap(),
 1391                String::new(),
 1392            )
 1393        });
 1394        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1395        Self::new(EditorMode::Full, buffer, None, cx)
 1396    }
 1397
 1398    pub fn auto_height(max_lines: usize, cx: &mut ViewContext<Self>) -> Self {
 1399        let buffer = cx.new_model(|cx| {
 1400            Buffer::new(
 1401                0,
 1402                BufferId::new(cx.entity_id().as_u64()).unwrap(),
 1403                String::new(),
 1404            )
 1405        });
 1406        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1407        Self::new(EditorMode::AutoHeight { max_lines }, buffer, None, cx)
 1408    }
 1409
 1410    pub fn for_buffer(
 1411        buffer: Model<Buffer>,
 1412        project: Option<Model<Project>>,
 1413        cx: &mut ViewContext<Self>,
 1414    ) -> Self {
 1415        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
 1416        Self::new(EditorMode::Full, buffer, project, cx)
 1417    }
 1418
 1419    pub fn for_multibuffer(
 1420        buffer: Model<MultiBuffer>,
 1421        project: Option<Model<Project>>,
 1422        cx: &mut ViewContext<Self>,
 1423    ) -> Self {
 1424        Self::new(EditorMode::Full, buffer, project, cx)
 1425    }
 1426
 1427    pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
 1428        let mut clone = Self::new(self.mode, self.buffer.clone(), self.project.clone(), cx);
 1429        self.display_map.update(cx, |display_map, cx| {
 1430            let snapshot = display_map.snapshot(cx);
 1431            clone.display_map.update(cx, |display_map, cx| {
 1432                display_map.set_state(&snapshot, cx);
 1433            });
 1434        });
 1435        clone.selections.clone_state(&self.selections);
 1436        clone.scroll_manager.clone_state(&self.scroll_manager);
 1437        clone.searchable = self.searchable;
 1438        clone
 1439    }
 1440
 1441    fn new(
 1442        mode: EditorMode,
 1443        buffer: Model<MultiBuffer>,
 1444        project: Option<Model<Project>>,
 1445        cx: &mut ViewContext<Self>,
 1446    ) -> Self {
 1447        let style = cx.text_style();
 1448        let font_size = style.font_size.to_pixels(cx.rem_size());
 1449        let display_map = cx.new_model(|cx| {
 1450            DisplayMap::new(buffer.clone(), style.font(), font_size, None, 2, 1, cx)
 1451        });
 1452
 1453        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1454
 1455        let blink_manager = cx.new_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1456
 1457        let soft_wrap_mode_override =
 1458            (mode == EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1459
 1460        let mut project_subscriptions = Vec::new();
 1461        if mode == EditorMode::Full {
 1462            if let Some(project) = project.as_ref() {
 1463                if buffer.read(cx).is_singleton() {
 1464                    project_subscriptions.push(cx.observe(project, |_, _, cx| {
 1465                        cx.emit(EditorEvent::TitleChanged);
 1466                    }));
 1467                }
 1468                project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| {
 1469                    if let project::Event::RefreshInlayHints = event {
 1470                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1471                    };
 1472                }));
 1473            }
 1474        }
 1475
 1476        let inlay_hint_settings = inlay_hint_settings(
 1477            selections.newest_anchor().head(),
 1478            &buffer.read(cx).snapshot(cx),
 1479            cx,
 1480        );
 1481
 1482        let focus_handle = cx.focus_handle();
 1483        cx.on_focus(&focus_handle, Self::handle_focus).detach();
 1484        cx.on_blur(&focus_handle, Self::handle_blur).detach();
 1485
 1486        let mut this = Self {
 1487            handle: cx.view().downgrade(),
 1488            focus_handle,
 1489            buffer: buffer.clone(),
 1490            display_map: display_map.clone(),
 1491            selections,
 1492            scroll_manager: ScrollManager::new(cx),
 1493            columnar_selection_tail: None,
 1494            add_selections_state: None,
 1495            select_next_state: None,
 1496            select_prev_state: None,
 1497            selection_history: Default::default(),
 1498            autoclose_regions: Default::default(),
 1499            snippet_stack: Default::default(),
 1500            select_larger_syntax_node_stack: Vec::new(),
 1501            ime_transaction: Default::default(),
 1502            active_diagnostics: None,
 1503            soft_wrap_mode_override,
 1504            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1505            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1506            project,
 1507            blink_manager: blink_manager.clone(),
 1508            show_local_selections: true,
 1509            mode,
 1510            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1511            show_gutter: mode == EditorMode::Full,
 1512            show_wrap_guides: None,
 1513            placeholder_text: None,
 1514            highlighted_rows: None,
 1515            background_highlights: Default::default(),
 1516            inlay_background_highlights: Default::default(),
 1517            nav_history: None,
 1518            context_menu: RwLock::new(None),
 1519            mouse_context_menu: None,
 1520            completion_tasks: Default::default(),
 1521            next_completion_id: 0,
 1522            completion_documentation_pre_resolve_debounce: DebouncedDelay::new(),
 1523            next_inlay_id: 0,
 1524            available_code_actions: Default::default(),
 1525            code_actions_task: Default::default(),
 1526            document_highlights_task: Default::default(),
 1527            pending_rename: Default::default(),
 1528            searchable: true,
 1529            cursor_shape: Default::default(),
 1530            autoindent_mode: Some(AutoindentMode::EachLine),
 1531            collapse_matches: false,
 1532            workspace: None,
 1533            keymap_context_layers: Default::default(),
 1534            input_enabled: true,
 1535            use_modal_editing: mode == EditorMode::Full,
 1536            read_only: false,
 1537            use_autoclose: true,
 1538            leader_peer_id: None,
 1539            remote_id: None,
 1540            hover_state: Default::default(),
 1541            hovered_link_state: Default::default(),
 1542            copilot_state: Default::default(),
 1543            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1544            gutter_hovered: false,
 1545            pixel_position_of_newest_cursor: None,
 1546            gutter_width: Default::default(),
 1547            style: None,
 1548            show_cursor_names: false,
 1549            hovered_cursors: Default::default(),
 1550            editor_actions: Default::default(),
 1551            show_copilot_suggestions: mode == EditorMode::Full,
 1552            custom_context_menu: None,
 1553            _subscriptions: vec![
 1554                cx.observe(&buffer, Self::on_buffer_changed),
 1555                cx.subscribe(&buffer, Self::on_buffer_event),
 1556                cx.observe(&display_map, Self::on_display_map_changed),
 1557                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1558                cx.observe_global::<SettingsStore>(Self::settings_changed),
 1559                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1560                cx.observe_window_activation(|editor, cx| {
 1561                    let active = cx.is_window_active();
 1562                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1563                        if active {
 1564                            blink_manager.enable(cx);
 1565                        } else {
 1566                            blink_manager.show_cursor(cx);
 1567                            blink_manager.disable(cx);
 1568                        }
 1569                    });
 1570                }),
 1571            ],
 1572        };
 1573
 1574        this._subscriptions.extend(project_subscriptions);
 1575
 1576        this.end_selection(cx);
 1577        this.scroll_manager.show_scrollbar(cx);
 1578
 1579        if mode == EditorMode::Full {
 1580            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1581            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1582        }
 1583
 1584        this.report_editor_event("open", None, cx);
 1585        this
 1586    }
 1587
 1588    fn key_context(&self, cx: &AppContext) -> KeyContext {
 1589        let mut key_context = KeyContext::default();
 1590        key_context.add("Editor");
 1591        let mode = match self.mode {
 1592            EditorMode::SingleLine => "single_line",
 1593            EditorMode::AutoHeight { .. } => "auto_height",
 1594            EditorMode::Full => "full",
 1595        };
 1596        key_context.set("mode", mode);
 1597        if self.pending_rename.is_some() {
 1598            key_context.add("renaming");
 1599        }
 1600        if self.context_menu_visible() {
 1601            match self.context_menu.read().as_ref() {
 1602                Some(ContextMenu::Completions(_)) => {
 1603                    key_context.add("menu");
 1604                    key_context.add("showing_completions")
 1605                }
 1606                Some(ContextMenu::CodeActions(_)) => {
 1607                    key_context.add("menu");
 1608                    key_context.add("showing_code_actions")
 1609                }
 1610                None => {}
 1611            }
 1612        }
 1613
 1614        for layer in self.keymap_context_layers.values() {
 1615            key_context.extend(layer);
 1616        }
 1617
 1618        if let Some(extension) = self
 1619            .buffer
 1620            .read(cx)
 1621            .as_singleton()
 1622            .and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str())
 1623        {
 1624            key_context.set("extension", extension.to_string());
 1625        }
 1626
 1627        key_context
 1628    }
 1629
 1630    pub fn new_file(
 1631        workspace: &mut Workspace,
 1632        _: &workspace::NewFile,
 1633        cx: &mut ViewContext<Workspace>,
 1634    ) {
 1635        let project = workspace.project().clone();
 1636        if project.read(cx).is_remote() {
 1637            cx.propagate();
 1638        } else if let Some(buffer) = project
 1639            .update(cx, |project, cx| project.create_buffer("", None, cx))
 1640            .log_err()
 1641        {
 1642            workspace.add_item(
 1643                Box::new(cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
 1644                cx,
 1645            );
 1646        }
 1647    }
 1648
 1649    pub fn new_file_in_direction(
 1650        workspace: &mut Workspace,
 1651        action: &workspace::NewFileInDirection,
 1652        cx: &mut ViewContext<Workspace>,
 1653    ) {
 1654        let project = workspace.project().clone();
 1655        if project.read(cx).is_remote() {
 1656            cx.propagate();
 1657        } else if let Some(buffer) = project
 1658            .update(cx, |project, cx| project.create_buffer("", None, cx))
 1659            .log_err()
 1660        {
 1661            workspace.split_item(
 1662                action.0,
 1663                Box::new(cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
 1664                cx,
 1665            );
 1666        }
 1667    }
 1668
 1669    pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
 1670        self.buffer.read(cx).replica_id()
 1671    }
 1672
 1673    pub fn leader_peer_id(&self) -> Option<PeerId> {
 1674        self.leader_peer_id
 1675    }
 1676
 1677    pub fn buffer(&self) -> &Model<MultiBuffer> {
 1678        &self.buffer
 1679    }
 1680
 1681    pub fn workspace(&self) -> Option<View<Workspace>> {
 1682        self.workspace.as_ref()?.0.upgrade()
 1683    }
 1684
 1685    pub fn pane(&self, cx: &AppContext) -> Option<View<Pane>> {
 1686        self.workspace()?.read(cx).pane_for(&self.handle.upgrade()?)
 1687    }
 1688
 1689    pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
 1690        self.buffer().read(cx).title(cx)
 1691    }
 1692
 1693    pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot {
 1694        EditorSnapshot {
 1695            mode: self.mode,
 1696            show_gutter: self.show_gutter,
 1697            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 1698            scroll_anchor: self.scroll_manager.anchor(),
 1699            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 1700            placeholder_text: self.placeholder_text.clone(),
 1701            is_focused: self.focus_handle.is_focused(cx),
 1702        }
 1703    }
 1704
 1705    pub fn language_at<'a, T: ToOffset>(
 1706        &self,
 1707        point: T,
 1708        cx: &'a AppContext,
 1709    ) -> Option<Arc<Language>> {
 1710        self.buffer.read(cx).language_at(point, cx)
 1711    }
 1712
 1713    pub fn file_at<'a, T: ToOffset>(
 1714        &self,
 1715        point: T,
 1716        cx: &'a AppContext,
 1717    ) -> Option<Arc<dyn language::File>> {
 1718        self.buffer.read(cx).read(cx).file_at(point).cloned()
 1719    }
 1720
 1721    pub fn active_excerpt(
 1722        &self,
 1723        cx: &AppContext,
 1724    ) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
 1725        self.buffer
 1726            .read(cx)
 1727            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 1728    }
 1729
 1730    pub fn mode(&self) -> EditorMode {
 1731        self.mode
 1732    }
 1733
 1734    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 1735        self.collaboration_hub.as_deref()
 1736    }
 1737
 1738    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 1739        self.collaboration_hub = Some(hub);
 1740    }
 1741
 1742    pub fn set_custom_context_menu(
 1743        &mut self,
 1744        f: impl 'static
 1745            + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,
 1746    ) {
 1747        self.custom_context_menu = Some(Box::new(f))
 1748    }
 1749
 1750    pub fn set_completion_provider(&mut self, hub: Box<dyn CompletionProvider>) {
 1751        self.completion_provider = Some(hub);
 1752    }
 1753
 1754    pub fn placeholder_text(&self) -> Option<&str> {
 1755        self.placeholder_text.as_deref()
 1756    }
 1757
 1758    pub fn set_placeholder_text(
 1759        &mut self,
 1760        placeholder_text: impl Into<Arc<str>>,
 1761        cx: &mut ViewContext<Self>,
 1762    ) {
 1763        let placeholder_text = Some(placeholder_text.into());
 1764        if self.placeholder_text != placeholder_text {
 1765            self.placeholder_text = placeholder_text;
 1766            cx.notify();
 1767        }
 1768    }
 1769
 1770    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
 1771        self.cursor_shape = cursor_shape;
 1772        cx.notify();
 1773    }
 1774
 1775    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 1776        self.collapse_matches = collapse_matches;
 1777    }
 1778
 1779    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 1780        if self.collapse_matches {
 1781            return range.start..range.start;
 1782        }
 1783        range.clone()
 1784    }
 1785
 1786    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
 1787        if self.display_map.read(cx).clip_at_line_ends != clip {
 1788            self.display_map
 1789                .update(cx, |map, _| map.clip_at_line_ends = clip);
 1790        }
 1791    }
 1792
 1793    pub fn set_keymap_context_layer<Tag: 'static>(
 1794        &mut self,
 1795        context: KeyContext,
 1796        cx: &mut ViewContext<Self>,
 1797    ) {
 1798        self.keymap_context_layers
 1799            .insert(TypeId::of::<Tag>(), context);
 1800        cx.notify();
 1801    }
 1802
 1803    pub fn remove_keymap_context_layer<Tag: 'static>(&mut self, cx: &mut ViewContext<Self>) {
 1804        self.keymap_context_layers.remove(&TypeId::of::<Tag>());
 1805        cx.notify();
 1806    }
 1807
 1808    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 1809        self.input_enabled = input_enabled;
 1810    }
 1811
 1812    pub fn set_autoindent(&mut self, autoindent: bool) {
 1813        if autoindent {
 1814            self.autoindent_mode = Some(AutoindentMode::EachLine);
 1815        } else {
 1816            self.autoindent_mode = None;
 1817        }
 1818    }
 1819
 1820    pub fn read_only(&self, cx: &AppContext) -> bool {
 1821        self.read_only || self.buffer.read(cx).read_only()
 1822    }
 1823
 1824    pub fn set_read_only(&mut self, read_only: bool) {
 1825        self.read_only = read_only;
 1826    }
 1827
 1828    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 1829        self.use_autoclose = autoclose;
 1830    }
 1831
 1832    pub fn set_show_copilot_suggestions(&mut self, show_copilot_suggestions: bool) {
 1833        self.show_copilot_suggestions = show_copilot_suggestions;
 1834    }
 1835
 1836    pub fn set_use_modal_editing(&mut self, to: bool) {
 1837        self.use_modal_editing = to;
 1838    }
 1839
 1840    pub fn use_modal_editing(&self) -> bool {
 1841        self.use_modal_editing
 1842    }
 1843
 1844    fn selections_did_change(
 1845        &mut self,
 1846        local: bool,
 1847        old_cursor_position: &Anchor,
 1848        cx: &mut ViewContext<Self>,
 1849    ) {
 1850        if self.focus_handle.is_focused(cx) && self.leader_peer_id.is_none() {
 1851            self.buffer.update(cx, |buffer, cx| {
 1852                buffer.set_active_selections(
 1853                    &self.selections.disjoint_anchors(),
 1854                    self.selections.line_mode,
 1855                    self.cursor_shape,
 1856                    cx,
 1857                )
 1858            });
 1859        }
 1860
 1861        let display_map = self
 1862            .display_map
 1863            .update(cx, |display_map, cx| display_map.snapshot(cx));
 1864        let buffer = &display_map.buffer_snapshot;
 1865        self.add_selections_state = None;
 1866        self.select_next_state = None;
 1867        self.select_prev_state = None;
 1868        self.select_larger_syntax_node_stack.clear();
 1869        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 1870        self.snippet_stack
 1871            .invalidate(&self.selections.disjoint_anchors(), buffer);
 1872        self.take_rename(false, cx);
 1873
 1874        let new_cursor_position = self.selections.newest_anchor().head();
 1875
 1876        self.push_to_nav_history(
 1877            old_cursor_position.clone(),
 1878            Some(new_cursor_position.to_point(buffer)),
 1879            cx,
 1880        );
 1881
 1882        if local {
 1883            let new_cursor_position = self.selections.newest_anchor().head();
 1884            let mut context_menu = self.context_menu.write();
 1885            let completion_menu = match context_menu.as_ref() {
 1886                Some(ContextMenu::Completions(menu)) => Some(menu),
 1887
 1888                _ => {
 1889                    *context_menu = None;
 1890                    None
 1891                }
 1892            };
 1893
 1894            if let Some(completion_menu) = completion_menu {
 1895                let cursor_position = new_cursor_position.to_offset(buffer);
 1896                let (word_range, kind) =
 1897                    buffer.surrounding_word(completion_menu.initial_position.clone());
 1898                if kind == Some(CharKind::Word)
 1899                    && word_range.to_inclusive().contains(&cursor_position)
 1900                {
 1901                    let mut completion_menu = completion_menu.clone();
 1902                    drop(context_menu);
 1903
 1904                    let query = Self::completion_query(buffer, cursor_position);
 1905                    cx.spawn(move |this, mut cx| async move {
 1906                        completion_menu
 1907                            .filter(query.as_deref(), cx.background_executor().clone())
 1908                            .await;
 1909
 1910                        this.update(&mut cx, |this, cx| {
 1911                            let mut context_menu = this.context_menu.write();
 1912                            let Some(ContextMenu::Completions(menu)) = context_menu.as_ref() else {
 1913                                return;
 1914                            };
 1915
 1916                            if menu.id > completion_menu.id {
 1917                                return;
 1918                            }
 1919
 1920                            *context_menu = Some(ContextMenu::Completions(completion_menu));
 1921                            drop(context_menu);
 1922                            cx.notify();
 1923                        })
 1924                    })
 1925                    .detach();
 1926
 1927                    self.show_completions(&ShowCompletions, cx);
 1928                } else {
 1929                    drop(context_menu);
 1930                    self.hide_context_menu(cx);
 1931                }
 1932            } else {
 1933                drop(context_menu);
 1934            }
 1935
 1936            hide_hover(self, cx);
 1937
 1938            if old_cursor_position.to_display_point(&display_map).row()
 1939                != new_cursor_position.to_display_point(&display_map).row()
 1940            {
 1941                self.available_code_actions.take();
 1942            }
 1943            self.refresh_code_actions(cx);
 1944            self.refresh_document_highlights(cx);
 1945            refresh_matching_bracket_highlights(self, cx);
 1946            self.discard_copilot_suggestion(cx);
 1947        }
 1948
 1949        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 1950        cx.emit(EditorEvent::SelectionsChanged { local });
 1951
 1952        if self.selections.disjoint_anchors().len() == 1 {
 1953            cx.emit(SearchEvent::ActiveMatchChanged)
 1954        }
 1955
 1956        cx.notify();
 1957    }
 1958
 1959    pub fn change_selections<R>(
 1960        &mut self,
 1961        autoscroll: Option<Autoscroll>,
 1962        cx: &mut ViewContext<Self>,
 1963        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 1964    ) -> R {
 1965        let old_cursor_position = self.selections.newest_anchor().head();
 1966        self.push_to_selection_history();
 1967
 1968        let (changed, result) = self.selections.change_with(cx, change);
 1969
 1970        if changed {
 1971            if let Some(autoscroll) = autoscroll {
 1972                self.request_autoscroll(autoscroll, cx);
 1973            }
 1974            self.selections_did_change(true, &old_cursor_position, cx);
 1975        }
 1976
 1977        result
 1978    }
 1979
 1980    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
 1981    where
 1982        I: IntoIterator<Item = (Range<S>, T)>,
 1983        S: ToOffset,
 1984        T: Into<Arc<str>>,
 1985    {
 1986        if self.read_only(cx) {
 1987            return;
 1988        }
 1989
 1990        self.buffer
 1991            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 1992    }
 1993
 1994    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
 1995    where
 1996        I: IntoIterator<Item = (Range<S>, T)>,
 1997        S: ToOffset,
 1998        T: Into<Arc<str>>,
 1999    {
 2000        if self.read_only(cx) {
 2001            return;
 2002        }
 2003
 2004        self.buffer.update(cx, |buffer, cx| {
 2005            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2006        });
 2007    }
 2008
 2009    pub fn edit_with_block_indent<I, S, T>(
 2010        &mut self,
 2011        edits: I,
 2012        original_indent_columns: Vec<u32>,
 2013        cx: &mut ViewContext<Self>,
 2014    ) where
 2015        I: IntoIterator<Item = (Range<S>, T)>,
 2016        S: ToOffset,
 2017        T: Into<Arc<str>>,
 2018    {
 2019        if self.read_only(cx) {
 2020            return;
 2021        }
 2022
 2023        self.buffer.update(cx, |buffer, cx| {
 2024            buffer.edit(
 2025                edits,
 2026                Some(AutoindentMode::Block {
 2027                    original_indent_columns,
 2028                }),
 2029                cx,
 2030            )
 2031        });
 2032    }
 2033
 2034    fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext<Self>) {
 2035        self.hide_context_menu(cx);
 2036
 2037        match phase {
 2038            SelectPhase::Begin {
 2039                position,
 2040                add,
 2041                click_count,
 2042            } => self.begin_selection(position, add, click_count, cx),
 2043            SelectPhase::BeginColumnar {
 2044                position,
 2045                goal_column,
 2046            } => self.begin_columnar_selection(position, goal_column, cx),
 2047            SelectPhase::Extend {
 2048                position,
 2049                click_count,
 2050            } => self.extend_selection(position, click_count, cx),
 2051            SelectPhase::Update {
 2052                position,
 2053                goal_column,
 2054                scroll_delta,
 2055            } => self.update_selection(position, goal_column, scroll_delta, cx),
 2056            SelectPhase::End => self.end_selection(cx),
 2057        }
 2058    }
 2059
 2060    fn extend_selection(
 2061        &mut self,
 2062        position: DisplayPoint,
 2063        click_count: usize,
 2064        cx: &mut ViewContext<Self>,
 2065    ) {
 2066        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2067        let tail = self.selections.newest::<usize>(cx).tail();
 2068        self.begin_selection(position, false, click_count, cx);
 2069
 2070        let position = position.to_offset(&display_map, Bias::Left);
 2071        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 2072
 2073        let mut pending_selection = self
 2074            .selections
 2075            .pending_anchor()
 2076            .expect("extend_selection not called with pending selection");
 2077        if position >= tail {
 2078            pending_selection.start = tail_anchor;
 2079        } else {
 2080            pending_selection.end = tail_anchor;
 2081            pending_selection.reversed = true;
 2082        }
 2083
 2084        let mut pending_mode = self.selections.pending_mode().unwrap();
 2085        match &mut pending_mode {
 2086            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 2087            _ => {}
 2088        }
 2089
 2090        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 2091            s.set_pending(pending_selection, pending_mode)
 2092        });
 2093    }
 2094
 2095    fn begin_selection(
 2096        &mut self,
 2097        position: DisplayPoint,
 2098        add: bool,
 2099        click_count: usize,
 2100        cx: &mut ViewContext<Self>,
 2101    ) {
 2102        if !self.focus_handle.is_focused(cx) {
 2103            cx.focus(&self.focus_handle);
 2104        }
 2105
 2106        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2107        let buffer = &display_map.buffer_snapshot;
 2108        let newest_selection = self.selections.newest_anchor().clone();
 2109        let position = display_map.clip_point(position, Bias::Left);
 2110
 2111        let start;
 2112        let end;
 2113        let mode;
 2114        let auto_scroll;
 2115        match click_count {
 2116            1 => {
 2117                start = buffer.anchor_before(position.to_point(&display_map));
 2118                end = start.clone();
 2119                mode = SelectMode::Character;
 2120                auto_scroll = true;
 2121            }
 2122            2 => {
 2123                let range = movement::surrounding_word(&display_map, position);
 2124                start = buffer.anchor_before(range.start.to_point(&display_map));
 2125                end = buffer.anchor_before(range.end.to_point(&display_map));
 2126                mode = SelectMode::Word(start.clone()..end.clone());
 2127                auto_scroll = true;
 2128            }
 2129            3 => {
 2130                let position = display_map
 2131                    .clip_point(position, Bias::Left)
 2132                    .to_point(&display_map);
 2133                let line_start = display_map.prev_line_boundary(position).0;
 2134                let next_line_start = buffer.clip_point(
 2135                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2136                    Bias::Left,
 2137                );
 2138                start = buffer.anchor_before(line_start);
 2139                end = buffer.anchor_before(next_line_start);
 2140                mode = SelectMode::Line(start.clone()..end.clone());
 2141                auto_scroll = true;
 2142            }
 2143            _ => {
 2144                start = buffer.anchor_before(0);
 2145                end = buffer.anchor_before(buffer.len());
 2146                mode = SelectMode::All;
 2147                auto_scroll = false;
 2148            }
 2149        }
 2150
 2151        self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| {
 2152            if !add {
 2153                s.clear_disjoint();
 2154            } else if click_count > 1 {
 2155                s.delete(newest_selection.id)
 2156            }
 2157
 2158            s.set_pending_anchor_range(start..end, mode);
 2159        });
 2160    }
 2161
 2162    fn begin_columnar_selection(
 2163        &mut self,
 2164        position: DisplayPoint,
 2165        goal_column: u32,
 2166        cx: &mut ViewContext<Self>,
 2167    ) {
 2168        if !self.focus_handle.is_focused(cx) {
 2169            cx.focus(&self.focus_handle);
 2170        }
 2171
 2172        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2173        let tail = self.selections.newest::<Point>(cx).tail();
 2174        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 2175
 2176        self.select_columns(
 2177            tail.to_display_point(&display_map),
 2178            position,
 2179            goal_column,
 2180            &display_map,
 2181            cx,
 2182        );
 2183    }
 2184
 2185    fn update_selection(
 2186        &mut self,
 2187        position: DisplayPoint,
 2188        goal_column: u32,
 2189        scroll_delta: gpui::Point<f32>,
 2190        cx: &mut ViewContext<Self>,
 2191    ) {
 2192        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 2193
 2194        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 2195            let tail = tail.to_display_point(&display_map);
 2196            self.select_columns(tail, position, goal_column, &display_map, cx);
 2197        } else if let Some(mut pending) = self.selections.pending_anchor() {
 2198            let buffer = self.buffer.read(cx).snapshot(cx);
 2199            let head;
 2200            let tail;
 2201            let mode = self.selections.pending_mode().unwrap();
 2202            match &mode {
 2203                SelectMode::Character => {
 2204                    head = position.to_point(&display_map);
 2205                    tail = pending.tail().to_point(&buffer);
 2206                }
 2207                SelectMode::Word(original_range) => {
 2208                    let original_display_range = original_range.start.to_display_point(&display_map)
 2209                        ..original_range.end.to_display_point(&display_map);
 2210                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 2211                        ..original_display_range.end.to_point(&display_map);
 2212                    if movement::is_inside_word(&display_map, position)
 2213                        || original_display_range.contains(&position)
 2214                    {
 2215                        let word_range = movement::surrounding_word(&display_map, position);
 2216                        if word_range.start < original_display_range.start {
 2217                            head = word_range.start.to_point(&display_map);
 2218                        } else {
 2219                            head = word_range.end.to_point(&display_map);
 2220                        }
 2221                    } else {
 2222                        head = position.to_point(&display_map);
 2223                    }
 2224
 2225                    if head <= original_buffer_range.start {
 2226                        tail = original_buffer_range.end;
 2227                    } else {
 2228                        tail = original_buffer_range.start;
 2229                    }
 2230                }
 2231                SelectMode::Line(original_range) => {
 2232                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 2233
 2234                    let position = display_map
 2235                        .clip_point(position, Bias::Left)
 2236                        .to_point(&display_map);
 2237                    let line_start = display_map.prev_line_boundary(position).0;
 2238                    let next_line_start = buffer.clip_point(
 2239                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 2240                        Bias::Left,
 2241                    );
 2242
 2243                    if line_start < original_range.start {
 2244                        head = line_start
 2245                    } else {
 2246                        head = next_line_start
 2247                    }
 2248
 2249                    if head <= original_range.start {
 2250                        tail = original_range.end;
 2251                    } else {
 2252                        tail = original_range.start;
 2253                    }
 2254                }
 2255                SelectMode::All => {
 2256                    return;
 2257                }
 2258            };
 2259
 2260            if head < tail {
 2261                pending.start = buffer.anchor_before(head);
 2262                pending.end = buffer.anchor_before(tail);
 2263                pending.reversed = true;
 2264            } else {
 2265                pending.start = buffer.anchor_before(tail);
 2266                pending.end = buffer.anchor_before(head);
 2267                pending.reversed = false;
 2268            }
 2269
 2270            self.change_selections(None, cx, |s| {
 2271                s.set_pending(pending, mode);
 2272            });
 2273        } else {
 2274            log::error!("update_selection dispatched with no pending selection");
 2275            return;
 2276        }
 2277
 2278        self.apply_scroll_delta(scroll_delta, cx);
 2279        cx.notify();
 2280    }
 2281
 2282    fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
 2283        self.columnar_selection_tail.take();
 2284        if self.selections.pending_anchor().is_some() {
 2285            let selections = self.selections.all::<usize>(cx);
 2286            self.change_selections(None, cx, |s| {
 2287                s.select(selections);
 2288                s.clear_pending();
 2289            });
 2290        }
 2291    }
 2292
 2293    fn select_columns(
 2294        &mut self,
 2295        tail: DisplayPoint,
 2296        head: DisplayPoint,
 2297        goal_column: u32,
 2298        display_map: &DisplaySnapshot,
 2299        cx: &mut ViewContext<Self>,
 2300    ) {
 2301        let start_row = cmp::min(tail.row(), head.row());
 2302        let end_row = cmp::max(tail.row(), head.row());
 2303        let start_column = cmp::min(tail.column(), goal_column);
 2304        let end_column = cmp::max(tail.column(), goal_column);
 2305        let reversed = start_column < tail.column();
 2306
 2307        let selection_ranges = (start_row..=end_row)
 2308            .filter_map(|row| {
 2309                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 2310                    let start = display_map
 2311                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 2312                        .to_point(display_map);
 2313                    let end = display_map
 2314                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 2315                        .to_point(display_map);
 2316                    if reversed {
 2317                        Some(end..start)
 2318                    } else {
 2319                        Some(start..end)
 2320                    }
 2321                } else {
 2322                    None
 2323                }
 2324            })
 2325            .collect::<Vec<_>>();
 2326
 2327        self.change_selections(None, cx, |s| {
 2328            s.select_ranges(selection_ranges);
 2329        });
 2330        cx.notify();
 2331    }
 2332
 2333    pub fn has_pending_nonempty_selection(&self) -> bool {
 2334        let pending_nonempty_selection = match self.selections.pending_anchor() {
 2335            Some(Selection { start, end, .. }) => start != end,
 2336            None => false,
 2337        };
 2338        pending_nonempty_selection || self.columnar_selection_tail.is_some()
 2339    }
 2340
 2341    pub fn has_pending_selection(&self) -> bool {
 2342        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 2343    }
 2344
 2345    pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
 2346        if self.take_rename(false, cx).is_some() {
 2347            return;
 2348        }
 2349
 2350        if hide_hover(self, cx) {
 2351            return;
 2352        }
 2353
 2354        if self.hide_context_menu(cx).is_some() {
 2355            return;
 2356        }
 2357
 2358        if self.discard_copilot_suggestion(cx) {
 2359            return;
 2360        }
 2361
 2362        if self.snippet_stack.pop().is_some() {
 2363            return;
 2364        }
 2365
 2366        if self.mode == EditorMode::Full {
 2367            if self.active_diagnostics.is_some() {
 2368                self.dismiss_diagnostics(cx);
 2369                return;
 2370            }
 2371
 2372            if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
 2373                return;
 2374            }
 2375        }
 2376
 2377        cx.propagate();
 2378    }
 2379
 2380    pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 2381        let text: Arc<str> = text.into();
 2382
 2383        if self.read_only(cx) {
 2384            return;
 2385        }
 2386
 2387        let selections = self.selections.all_adjusted(cx);
 2388        let mut brace_inserted = false;
 2389        let mut edits = Vec::new();
 2390        let mut new_selections = Vec::with_capacity(selections.len());
 2391        let mut new_autoclose_regions = Vec::new();
 2392        let snapshot = self.buffer.read(cx).read(cx);
 2393
 2394        for (selection, autoclose_region) in
 2395            self.selections_with_autoclose_regions(selections, &snapshot)
 2396        {
 2397            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 2398                // Determine if the inserted text matches the opening or closing
 2399                // bracket of any of this language's bracket pairs.
 2400                let mut bracket_pair = None;
 2401                let mut is_bracket_pair_start = false;
 2402                if !text.is_empty() {
 2403                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 2404                    //  and they are removing the character that triggered IME popup.
 2405                    for (pair, enabled) in scope.brackets() {
 2406                        if enabled && pair.close && pair.start.ends_with(text.as_ref()) {
 2407                            bracket_pair = Some(pair.clone());
 2408                            is_bracket_pair_start = true;
 2409                            break;
 2410                        } else if pair.end.as_str() == text.as_ref() {
 2411                            bracket_pair = Some(pair.clone());
 2412                            break;
 2413                        }
 2414                    }
 2415                }
 2416
 2417                if let Some(bracket_pair) = bracket_pair {
 2418                    if selection.is_empty() {
 2419                        if is_bracket_pair_start {
 2420                            let prefix_len = bracket_pair.start.len() - text.len();
 2421
 2422                            // If the inserted text is a suffix of an opening bracket and the
 2423                            // selection is preceded by the rest of the opening bracket, then
 2424                            // insert the closing bracket.
 2425                            let following_text_allows_autoclose = snapshot
 2426                                .chars_at(selection.start)
 2427                                .next()
 2428                                .map_or(true, |c| scope.should_autoclose_before(c));
 2429                            let preceding_text_matches_prefix = prefix_len == 0
 2430                                || (selection.start.column >= (prefix_len as u32)
 2431                                    && snapshot.contains_str_at(
 2432                                        Point::new(
 2433                                            selection.start.row,
 2434                                            selection.start.column - (prefix_len as u32),
 2435                                        ),
 2436                                        &bracket_pair.start[..prefix_len],
 2437                                    ));
 2438                            let autoclose = self.use_autoclose
 2439                                && snapshot.settings_at(selection.start, cx).use_autoclose;
 2440                            if autoclose
 2441                                && following_text_allows_autoclose
 2442                                && preceding_text_matches_prefix
 2443                            {
 2444                                let anchor = snapshot.anchor_before(selection.end);
 2445                                new_selections.push((selection.map(|_| anchor), text.len()));
 2446                                new_autoclose_regions.push((
 2447                                    anchor,
 2448                                    text.len(),
 2449                                    selection.id,
 2450                                    bracket_pair.clone(),
 2451                                ));
 2452                                edits.push((
 2453                                    selection.range(),
 2454                                    format!("{}{}", text, bracket_pair.end).into(),
 2455                                ));
 2456                                brace_inserted = true;
 2457                                continue;
 2458                            }
 2459                        }
 2460
 2461                        if let Some(region) = autoclose_region {
 2462                            // If the selection is followed by an auto-inserted closing bracket,
 2463                            // then don't insert that closing bracket again; just move the selection
 2464                            // past the closing bracket.
 2465                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 2466                                && text.as_ref() == region.pair.end.as_str();
 2467                            if should_skip {
 2468                                let anchor = snapshot.anchor_after(selection.end);
 2469                                new_selections
 2470                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 2471                                continue;
 2472                            }
 2473                        }
 2474                    }
 2475                    // If an opening bracket is 1 character long and is typed while
 2476                    // text is selected, then surround that text with the bracket pair.
 2477                    else if is_bracket_pair_start && bracket_pair.start.chars().count() == 1 {
 2478                        edits.push((selection.start..selection.start, text.clone()));
 2479                        edits.push((
 2480                            selection.end..selection.end,
 2481                            bracket_pair.end.as_str().into(),
 2482                        ));
 2483                        brace_inserted = true;
 2484                        new_selections.push((
 2485                            Selection {
 2486                                id: selection.id,
 2487                                start: snapshot.anchor_after(selection.start),
 2488                                end: snapshot.anchor_before(selection.end),
 2489                                reversed: selection.reversed,
 2490                                goal: selection.goal,
 2491                            },
 2492                            0,
 2493                        ));
 2494                        continue;
 2495                    }
 2496                }
 2497            }
 2498
 2499            // If not handling any auto-close operation, then just replace the selected
 2500            // text with the given input and move the selection to the end of the
 2501            // newly inserted text.
 2502            let anchor = snapshot.anchor_after(selection.end);
 2503            new_selections.push((selection.map(|_| anchor), 0));
 2504            edits.push((selection.start..selection.end, text.clone()));
 2505        }
 2506
 2507        drop(snapshot);
 2508        self.transact(cx, |this, cx| {
 2509            this.buffer.update(cx, |buffer, cx| {
 2510                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 2511            });
 2512
 2513            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 2514            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 2515            let snapshot = this.buffer.read(cx).read(cx);
 2516            let new_selections = resolve_multiple::<usize, _>(new_anchor_selections, &snapshot)
 2517                .zip(new_selection_deltas)
 2518                .map(|(selection, delta)| Selection {
 2519                    id: selection.id,
 2520                    start: selection.start + delta,
 2521                    end: selection.end + delta,
 2522                    reversed: selection.reversed,
 2523                    goal: SelectionGoal::None,
 2524                })
 2525                .collect::<Vec<_>>();
 2526
 2527            let mut i = 0;
 2528            for (position, delta, selection_id, pair) in new_autoclose_regions {
 2529                let position = position.to_offset(&snapshot) + delta;
 2530                let start = snapshot.anchor_before(position);
 2531                let end = snapshot.anchor_after(position);
 2532                while let Some(existing_state) = this.autoclose_regions.get(i) {
 2533                    match existing_state.range.start.cmp(&start, &snapshot) {
 2534                        Ordering::Less => i += 1,
 2535                        Ordering::Greater => break,
 2536                        Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) {
 2537                            Ordering::Less => i += 1,
 2538                            Ordering::Equal => break,
 2539                            Ordering::Greater => break,
 2540                        },
 2541                    }
 2542                }
 2543                this.autoclose_regions.insert(
 2544                    i,
 2545                    AutocloseRegion {
 2546                        selection_id,
 2547                        range: start..end,
 2548                        pair,
 2549                    },
 2550                );
 2551            }
 2552
 2553            drop(snapshot);
 2554            let had_active_copilot_suggestion = this.has_active_copilot_suggestion(cx);
 2555            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
 2556
 2557            if brace_inserted {
 2558                // If we inserted a brace while composing text (i.e. typing `"` on a
 2559                // Brazilian keyboard), exit the composing state because most likely
 2560                // the user wanted to surround the selection.
 2561                this.unmark_text(cx);
 2562            } else if EditorSettings::get_global(cx).use_on_type_format {
 2563                if let Some(on_type_format_task) =
 2564                    this.trigger_on_type_formatting(text.to_string(), cx)
 2565                {
 2566                    on_type_format_task.detach_and_log_err(cx);
 2567                }
 2568            }
 2569
 2570            if had_active_copilot_suggestion {
 2571                this.refresh_copilot_suggestions(true, cx);
 2572                if !this.has_active_copilot_suggestion(cx) {
 2573                    this.trigger_completion_on_input(&text, cx);
 2574                }
 2575            } else {
 2576                this.trigger_completion_on_input(&text, cx);
 2577                this.refresh_copilot_suggestions(true, cx);
 2578            }
 2579        });
 2580    }
 2581
 2582    pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
 2583        self.transact(cx, |this, cx| {
 2584            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
 2585                let selections = this.selections.all::<usize>(cx);
 2586                let multi_buffer = this.buffer.read(cx);
 2587                let buffer = multi_buffer.snapshot(cx);
 2588                selections
 2589                    .iter()
 2590                    .map(|selection| {
 2591                        let start_point = selection.start.to_point(&buffer);
 2592                        let mut indent = buffer.indent_size_for_line(start_point.row);
 2593                        indent.len = cmp::min(indent.len, start_point.column);
 2594                        let start = selection.start;
 2595                        let end = selection.end;
 2596                        let is_cursor = start == end;
 2597                        let language_scope = buffer.language_scope_at(start);
 2598                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
 2599                            &language_scope
 2600                        {
 2601                            let leading_whitespace_len = buffer
 2602                                .reversed_chars_at(start)
 2603                                .take_while(|c| c.is_whitespace() && *c != '\n')
 2604                                .map(|c| c.len_utf8())
 2605                                .sum::<usize>();
 2606
 2607                            let trailing_whitespace_len = buffer
 2608                                .chars_at(end)
 2609                                .take_while(|c| c.is_whitespace() && *c != '\n')
 2610                                .map(|c| c.len_utf8())
 2611                                .sum::<usize>();
 2612
 2613                            let insert_extra_newline =
 2614                                language.brackets().any(|(pair, enabled)| {
 2615                                    let pair_start = pair.start.trim_end();
 2616                                    let pair_end = pair.end.trim_start();
 2617
 2618                                    enabled
 2619                                        && pair.newline
 2620                                        && buffer.contains_str_at(
 2621                                            end + trailing_whitespace_len,
 2622                                            pair_end,
 2623                                        )
 2624                                        && buffer.contains_str_at(
 2625                                            (start - leading_whitespace_len)
 2626                                                .saturating_sub(pair_start.len()),
 2627                                            pair_start,
 2628                                        )
 2629                                });
 2630                            // Comment extension on newline is allowed only for cursor selections
 2631                            let comment_delimiter = language.line_comment_prefixes().filter(|_| {
 2632                                let is_comment_extension_enabled =
 2633                                    multi_buffer.settings_at(0, cx).extend_comment_on_newline;
 2634                                is_cursor && is_comment_extension_enabled
 2635                            });
 2636                            let get_comment_delimiter = |delimiters: &[Arc<str>]| {
 2637                                let max_len_of_delimiter =
 2638                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 2639                                let (snapshot, range) =
 2640                                    buffer.buffer_line_for_row(start_point.row)?;
 2641
 2642                                let mut index_of_first_non_whitespace = 0;
 2643                                let comment_candidate = snapshot
 2644                                    .chars_for_range(range)
 2645                                    .skip_while(|c| {
 2646                                        let should_skip = c.is_whitespace();
 2647                                        if should_skip {
 2648                                            index_of_first_non_whitespace += 1;
 2649                                        }
 2650                                        should_skip
 2651                                    })
 2652                                    .take(max_len_of_delimiter)
 2653                                    .collect::<String>();
 2654                                let comment_prefix = delimiters.iter().find(|comment_prefix| {
 2655                                    comment_candidate.starts_with(comment_prefix.as_ref())
 2656                                })?;
 2657                                let cursor_is_placed_after_comment_marker =
 2658                                    index_of_first_non_whitespace + comment_prefix.len()
 2659                                        <= start_point.column as usize;
 2660                                if cursor_is_placed_after_comment_marker {
 2661                                    Some(comment_prefix.clone())
 2662                                } else {
 2663                                    None
 2664                                }
 2665                            };
 2666                            let comment_delimiter = if let Some(delimiters) = comment_delimiter {
 2667                                get_comment_delimiter(delimiters)
 2668                            } else {
 2669                                None
 2670                            };
 2671                            (comment_delimiter, insert_extra_newline)
 2672                        } else {
 2673                            (None, false)
 2674                        };
 2675
 2676                        let capacity_for_delimiter = comment_delimiter
 2677                            .as_deref()
 2678                            .map(str::len)
 2679                            .unwrap_or_default();
 2680                        let mut new_text =
 2681                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
 2682                        new_text.push_str("\n");
 2683                        new_text.extend(indent.chars());
 2684                        if let Some(delimiter) = &comment_delimiter {
 2685                            new_text.push_str(&delimiter);
 2686                        }
 2687                        if insert_extra_newline {
 2688                            new_text = new_text.repeat(2);
 2689                        }
 2690
 2691                        let anchor = buffer.anchor_after(end);
 2692                        let new_selection = selection.map(|_| anchor);
 2693                        (
 2694                            (start..end, new_text),
 2695                            (insert_extra_newline, new_selection),
 2696                        )
 2697                    })
 2698                    .unzip()
 2699            };
 2700
 2701            this.edit_with_autoindent(edits, cx);
 2702            let buffer = this.buffer.read(cx).snapshot(cx);
 2703            let new_selections = selection_fixup_info
 2704                .into_iter()
 2705                .map(|(extra_newline_inserted, new_selection)| {
 2706                    let mut cursor = new_selection.end.to_point(&buffer);
 2707                    if extra_newline_inserted {
 2708                        cursor.row -= 1;
 2709                        cursor.column = buffer.line_len(cursor.row);
 2710                    }
 2711                    new_selection.map(|_| cursor)
 2712                })
 2713                .collect();
 2714
 2715            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
 2716            this.refresh_copilot_suggestions(true, cx);
 2717        });
 2718    }
 2719
 2720    pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext<Self>) {
 2721        let buffer = self.buffer.read(cx);
 2722        let snapshot = buffer.snapshot(cx);
 2723
 2724        let mut edits = Vec::new();
 2725        let mut rows = Vec::new();
 2726        let mut rows_inserted = 0;
 2727
 2728        for selection in self.selections.all_adjusted(cx) {
 2729            let cursor = selection.head();
 2730            let row = cursor.row;
 2731
 2732            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 2733
 2734            let newline = "\n".to_string();
 2735            edits.push((start_of_line..start_of_line, newline));
 2736
 2737            rows.push(row + rows_inserted);
 2738            rows_inserted += 1;
 2739        }
 2740
 2741        self.transact(cx, |editor, cx| {
 2742            editor.edit(edits, cx);
 2743
 2744            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 2745                let mut index = 0;
 2746                s.move_cursors_with(|map, _, _| {
 2747                    let row = rows[index];
 2748                    index += 1;
 2749
 2750                    let point = Point::new(row, 0);
 2751                    let boundary = map.next_line_boundary(point).1;
 2752                    let clipped = map.clip_point(boundary, Bias::Left);
 2753
 2754                    (clipped, SelectionGoal::None)
 2755                });
 2756            });
 2757
 2758            let mut indent_edits = Vec::new();
 2759            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 2760            for row in rows {
 2761                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 2762                for (row, indent) in indents {
 2763                    if indent.len == 0 {
 2764                        continue;
 2765                    }
 2766
 2767                    let text = match indent.kind {
 2768                        IndentKind::Space => " ".repeat(indent.len as usize),
 2769                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 2770                    };
 2771                    let point = Point::new(row, 0);
 2772                    indent_edits.push((point..point, text));
 2773                }
 2774            }
 2775            editor.edit(indent_edits, cx);
 2776        });
 2777    }
 2778
 2779    pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
 2780        let buffer = self.buffer.read(cx);
 2781        let snapshot = buffer.snapshot(cx);
 2782
 2783        let mut edits = Vec::new();
 2784        let mut rows = Vec::new();
 2785        let mut rows_inserted = 0;
 2786
 2787        for selection in self.selections.all_adjusted(cx) {
 2788            let cursor = selection.head();
 2789            let row = cursor.row;
 2790
 2791            let point = Point::new(row + 1, 0);
 2792            let start_of_line = snapshot.clip_point(point, Bias::Left);
 2793
 2794            let newline = "\n".to_string();
 2795            edits.push((start_of_line..start_of_line, newline));
 2796
 2797            rows_inserted += 1;
 2798            rows.push(row + rows_inserted);
 2799        }
 2800
 2801        self.transact(cx, |editor, cx| {
 2802            editor.edit(edits, cx);
 2803
 2804            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 2805                let mut index = 0;
 2806                s.move_cursors_with(|map, _, _| {
 2807                    let row = rows[index];
 2808                    index += 1;
 2809
 2810                    let point = Point::new(row, 0);
 2811                    let boundary = map.next_line_boundary(point).1;
 2812                    let clipped = map.clip_point(boundary, Bias::Left);
 2813
 2814                    (clipped, SelectionGoal::None)
 2815                });
 2816            });
 2817
 2818            let mut indent_edits = Vec::new();
 2819            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 2820            for row in rows {
 2821                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 2822                for (row, indent) in indents {
 2823                    if indent.len == 0 {
 2824                        continue;
 2825                    }
 2826
 2827                    let text = match indent.kind {
 2828                        IndentKind::Space => " ".repeat(indent.len as usize),
 2829                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 2830                    };
 2831                    let point = Point::new(row, 0);
 2832                    indent_edits.push((point..point, text));
 2833                }
 2834            }
 2835            editor.edit(indent_edits, cx);
 2836        });
 2837    }
 2838
 2839    pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 2840        self.insert_with_autoindent_mode(
 2841            text,
 2842            Some(AutoindentMode::Block {
 2843                original_indent_columns: Vec::new(),
 2844            }),
 2845            cx,
 2846        );
 2847    }
 2848
 2849    fn insert_with_autoindent_mode(
 2850        &mut self,
 2851        text: &str,
 2852        autoindent_mode: Option<AutoindentMode>,
 2853        cx: &mut ViewContext<Self>,
 2854    ) {
 2855        if self.read_only(cx) {
 2856            return;
 2857        }
 2858
 2859        let text: Arc<str> = text.into();
 2860        self.transact(cx, |this, cx| {
 2861            let old_selections = this.selections.all_adjusted(cx);
 2862            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 2863                let anchors = {
 2864                    let snapshot = buffer.read(cx);
 2865                    old_selections
 2866                        .iter()
 2867                        .map(|s| {
 2868                            let anchor = snapshot.anchor_after(s.head());
 2869                            s.map(|_| anchor)
 2870                        })
 2871                        .collect::<Vec<_>>()
 2872                };
 2873                buffer.edit(
 2874                    old_selections
 2875                        .iter()
 2876                        .map(|s| (s.start..s.end, text.clone())),
 2877                    autoindent_mode,
 2878                    cx,
 2879                );
 2880                anchors
 2881            });
 2882
 2883            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 2884                s.select_anchors(selection_anchors);
 2885            })
 2886        });
 2887    }
 2888
 2889    fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
 2890        if !EditorSettings::get_global(cx).show_completions_on_input {
 2891            return;
 2892        }
 2893
 2894        let selection = self.selections.newest_anchor();
 2895        if self
 2896            .buffer
 2897            .read(cx)
 2898            .is_completion_trigger(selection.head(), text, cx)
 2899        {
 2900            self.show_completions(&ShowCompletions, cx);
 2901        } else {
 2902            self.hide_context_menu(cx);
 2903        }
 2904    }
 2905
 2906    /// If any empty selections is touching the start of its innermost containing autoclose
 2907    /// region, expand it to select the brackets.
 2908    fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
 2909        let selections = self.selections.all::<usize>(cx);
 2910        let buffer = self.buffer.read(cx).read(cx);
 2911        let mut new_selections = Vec::new();
 2912        for (mut selection, region) in self.selections_with_autoclose_regions(selections, &buffer) {
 2913            if let (Some(region), true) = (region, selection.is_empty()) {
 2914                let mut range = region.range.to_offset(&buffer);
 2915                if selection.start == range.start {
 2916                    if range.start >= region.pair.start.len() {
 2917                        range.start -= region.pair.start.len();
 2918                        if buffer.contains_str_at(range.start, &region.pair.start) {
 2919                            if buffer.contains_str_at(range.end, &region.pair.end) {
 2920                                range.end += region.pair.end.len();
 2921                                selection.start = range.start;
 2922                                selection.end = range.end;
 2923                            }
 2924                        }
 2925                    }
 2926                }
 2927            }
 2928            new_selections.push(selection);
 2929        }
 2930
 2931        drop(buffer);
 2932        self.change_selections(None, cx, |selections| selections.select(new_selections));
 2933    }
 2934
 2935    /// Iterate the given selections, and for each one, find the smallest surrounding
 2936    /// autoclose region. This uses the ordering of the selections and the autoclose
 2937    /// regions to avoid repeated comparisons.
 2938    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 2939        &'a self,
 2940        selections: impl IntoIterator<Item = Selection<D>>,
 2941        buffer: &'a MultiBufferSnapshot,
 2942    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 2943        let mut i = 0;
 2944        let mut regions = self.autoclose_regions.as_slice();
 2945        selections.into_iter().map(move |selection| {
 2946            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 2947
 2948            let mut enclosing = None;
 2949            while let Some(pair_state) = regions.get(i) {
 2950                if pair_state.range.end.to_offset(buffer) < range.start {
 2951                    regions = &regions[i + 1..];
 2952                    i = 0;
 2953                } else if pair_state.range.start.to_offset(buffer) > range.end {
 2954                    break;
 2955                } else {
 2956                    if pair_state.selection_id == selection.id {
 2957                        enclosing = Some(pair_state);
 2958                    }
 2959                    i += 1;
 2960                }
 2961            }
 2962
 2963            (selection.clone(), enclosing)
 2964        })
 2965    }
 2966
 2967    /// Remove any autoclose regions that no longer contain their selection.
 2968    fn invalidate_autoclose_regions(
 2969        &mut self,
 2970        mut selections: &[Selection<Anchor>],
 2971        buffer: &MultiBufferSnapshot,
 2972    ) {
 2973        self.autoclose_regions.retain(|state| {
 2974            let mut i = 0;
 2975            while let Some(selection) = selections.get(i) {
 2976                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 2977                    selections = &selections[1..];
 2978                    continue;
 2979                }
 2980                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 2981                    break;
 2982                }
 2983                if selection.id == state.selection_id {
 2984                    return true;
 2985                } else {
 2986                    i += 1;
 2987                }
 2988            }
 2989            false
 2990        });
 2991    }
 2992
 2993    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 2994        let offset = position.to_offset(buffer);
 2995        let (word_range, kind) = buffer.surrounding_word(offset);
 2996        if offset > word_range.start && kind == Some(CharKind::Word) {
 2997            Some(
 2998                buffer
 2999                    .text_for_range(word_range.start..offset)
 3000                    .collect::<String>(),
 3001            )
 3002        } else {
 3003            None
 3004        }
 3005    }
 3006
 3007    pub fn toggle_inlay_hints(&mut self, _: &ToggleInlayHints, cx: &mut ViewContext<Self>) {
 3008        self.refresh_inlay_hints(
 3009            InlayHintRefreshReason::Toggle(!self.inlay_hint_cache.enabled),
 3010            cx,
 3011        );
 3012    }
 3013
 3014    pub fn inlay_hints_enabled(&self) -> bool {
 3015        self.inlay_hint_cache.enabled
 3016    }
 3017
 3018    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut ViewContext<Self>) {
 3019        if self.project.is_none() || self.mode != EditorMode::Full {
 3020            return;
 3021        }
 3022
 3023        let reason_description = reason.description();
 3024        let (invalidate_cache, required_languages) = match reason {
 3025            InlayHintRefreshReason::Toggle(enabled) => {
 3026                self.inlay_hint_cache.enabled = enabled;
 3027                if enabled {
 3028                    (InvalidationStrategy::RefreshRequested, None)
 3029                } else {
 3030                    self.inlay_hint_cache.clear();
 3031                    self.splice_inlay_hints(
 3032                        self.visible_inlay_hints(cx)
 3033                            .iter()
 3034                            .map(|inlay| inlay.id)
 3035                            .collect(),
 3036                        Vec::new(),
 3037                        cx,
 3038                    );
 3039                    return;
 3040                }
 3041            }
 3042            InlayHintRefreshReason::SettingsChange(new_settings) => {
 3043                match self.inlay_hint_cache.update_settings(
 3044                    &self.buffer,
 3045                    new_settings,
 3046                    self.visible_inlay_hints(cx),
 3047                    cx,
 3048                ) {
 3049                    ControlFlow::Break(Some(InlaySplice {
 3050                        to_remove,
 3051                        to_insert,
 3052                    })) => {
 3053                        self.splice_inlay_hints(to_remove, to_insert, cx);
 3054                        return;
 3055                    }
 3056                    ControlFlow::Break(None) => return,
 3057                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 3058                }
 3059            }
 3060            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 3061                if let Some(InlaySplice {
 3062                    to_remove,
 3063                    to_insert,
 3064                }) = self.inlay_hint_cache.remove_excerpts(excerpts_removed)
 3065                {
 3066                    self.splice_inlay_hints(to_remove, to_insert, cx);
 3067                }
 3068                return;
 3069            }
 3070            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 3071            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 3072                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 3073            }
 3074            InlayHintRefreshReason::RefreshRequested => {
 3075                (InvalidationStrategy::RefreshRequested, None)
 3076            }
 3077        };
 3078
 3079        if let Some(InlaySplice {
 3080            to_remove,
 3081            to_insert,
 3082        }) = self.inlay_hint_cache.spawn_hint_refresh(
 3083            reason_description,
 3084            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 3085            invalidate_cache,
 3086            cx,
 3087        ) {
 3088            self.splice_inlay_hints(to_remove, to_insert, cx);
 3089        }
 3090    }
 3091
 3092    fn visible_inlay_hints(&self, cx: &ViewContext<'_, Editor>) -> Vec<Inlay> {
 3093        self.display_map
 3094            .read(cx)
 3095            .current_inlays()
 3096            .filter(move |inlay| {
 3097                Some(inlay.id) != self.copilot_state.suggestion.as_ref().map(|h| h.id)
 3098            })
 3099            .cloned()
 3100            .collect()
 3101    }
 3102
 3103    pub fn excerpts_for_inlay_hints_query(
 3104        &self,
 3105        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 3106        cx: &mut ViewContext<Editor>,
 3107    ) -> HashMap<ExcerptId, (Model<Buffer>, clock::Global, Range<usize>)> {
 3108        let Some(project) = self.project.as_ref() else {
 3109            return HashMap::default();
 3110        };
 3111        let project = project.read(cx);
 3112        let multi_buffer = self.buffer().read(cx);
 3113        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 3114        let multi_buffer_visible_start = self
 3115            .scroll_manager
 3116            .anchor()
 3117            .anchor
 3118            .to_point(&multi_buffer_snapshot);
 3119        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 3120            multi_buffer_visible_start
 3121                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 3122            Bias::Left,
 3123        );
 3124        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 3125        multi_buffer
 3126            .range_to_buffer_ranges(multi_buffer_visible_range, cx)
 3127            .into_iter()
 3128            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 3129            .filter_map(|(buffer_handle, excerpt_visible_range, excerpt_id)| {
 3130                let buffer = buffer_handle.read(cx);
 3131                let buffer_file = project::worktree::File::from_dyn(buffer.file())?;
 3132                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 3133                let worktree_entry = buffer_worktree
 3134                    .read(cx)
 3135                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 3136                if worktree_entry.is_ignored {
 3137                    return None;
 3138                }
 3139
 3140                let language = buffer.language()?;
 3141                if let Some(restrict_to_languages) = restrict_to_languages {
 3142                    if !restrict_to_languages.contains(language) {
 3143                        return None;
 3144                    }
 3145                }
 3146                Some((
 3147                    excerpt_id,
 3148                    (
 3149                        buffer_handle,
 3150                        buffer.version().clone(),
 3151                        excerpt_visible_range,
 3152                    ),
 3153                ))
 3154            })
 3155            .collect()
 3156    }
 3157
 3158    pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails {
 3159        TextLayoutDetails {
 3160            text_system: cx.text_system().clone(),
 3161            editor_style: self.style.clone().unwrap(),
 3162            rem_size: cx.rem_size(),
 3163            scroll_anchor: self.scroll_manager.anchor(),
 3164            visible_rows: self.visible_line_count(),
 3165            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 3166        }
 3167    }
 3168
 3169    fn splice_inlay_hints(
 3170        &self,
 3171        to_remove: Vec<InlayId>,
 3172        to_insert: Vec<Inlay>,
 3173        cx: &mut ViewContext<Self>,
 3174    ) {
 3175        self.display_map.update(cx, |display_map, cx| {
 3176            display_map.splice_inlays(to_remove, to_insert, cx);
 3177        });
 3178        cx.notify();
 3179    }
 3180
 3181    fn trigger_on_type_formatting(
 3182        &self,
 3183        input: String,
 3184        cx: &mut ViewContext<Self>,
 3185    ) -> Option<Task<Result<()>>> {
 3186        if input.len() != 1 {
 3187            return None;
 3188        }
 3189
 3190        let project = self.project.as_ref()?;
 3191        let position = self.selections.newest_anchor().head();
 3192        let (buffer, buffer_position) = self
 3193            .buffer
 3194            .read(cx)
 3195            .text_anchor_for_position(position.clone(), cx)?;
 3196
 3197        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 3198        // hence we do LSP request & edit on host side only — add formats to host's history.
 3199        let push_to_lsp_host_history = true;
 3200        // If this is not the host, append its history with new edits.
 3201        let push_to_client_history = project.read(cx).is_remote();
 3202
 3203        let on_type_formatting = project.update(cx, |project, cx| {
 3204            project.on_type_format(
 3205                buffer.clone(),
 3206                buffer_position,
 3207                input,
 3208                push_to_lsp_host_history,
 3209                cx,
 3210            )
 3211        });
 3212        Some(cx.spawn(|editor, mut cx| async move {
 3213            if let Some(transaction) = on_type_formatting.await? {
 3214                if push_to_client_history {
 3215                    buffer
 3216                        .update(&mut cx, |buffer, _| {
 3217                            buffer.push_transaction(transaction, Instant::now());
 3218                        })
 3219                        .ok();
 3220                }
 3221                editor.update(&mut cx, |editor, cx| {
 3222                    editor.refresh_document_highlights(cx);
 3223                })?;
 3224            }
 3225            Ok(())
 3226        }))
 3227    }
 3228
 3229    fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
 3230        if self.pending_rename.is_some() {
 3231            return;
 3232        }
 3233
 3234        let Some(provider) = self.completion_provider.as_ref() else {
 3235            return;
 3236        };
 3237
 3238        let position = self.selections.newest_anchor().head();
 3239        let (buffer, buffer_position) = if let Some(output) = self
 3240            .buffer
 3241            .read(cx)
 3242            .text_anchor_for_position(position.clone(), cx)
 3243        {
 3244            output
 3245        } else {
 3246            return;
 3247        };
 3248
 3249        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
 3250        let completions = provider.completions(&buffer, buffer_position, cx);
 3251
 3252        let id = post_inc(&mut self.next_completion_id);
 3253        let task = cx.spawn(|this, mut cx| {
 3254            async move {
 3255                let completions = completions.await.log_err();
 3256                let menu = if let Some(completions) = completions {
 3257                    let mut menu = CompletionsMenu {
 3258                        id,
 3259                        initial_position: position,
 3260                        match_candidates: completions
 3261                            .iter()
 3262                            .enumerate()
 3263                            .map(|(id, completion)| {
 3264                                StringMatchCandidate::new(
 3265                                    id,
 3266                                    completion.label.text[completion.label.filter_range.clone()]
 3267                                        .into(),
 3268                                )
 3269                            })
 3270                            .collect(),
 3271                        buffer,
 3272                        completions: Arc::new(RwLock::new(completions.into())),
 3273                        matches: Vec::new().into(),
 3274                        selected_item: 0,
 3275                        scroll_handle: UniformListScrollHandle::new(),
 3276                        selected_completion_documentation_resolve_debounce: Arc::new(Mutex::new(
 3277                            DebouncedDelay::new(),
 3278                        )),
 3279                    };
 3280                    menu.filter(query.as_deref(), cx.background_executor().clone())
 3281                        .await;
 3282
 3283                    if menu.matches.is_empty() {
 3284                        None
 3285                    } else {
 3286                        this.update(&mut cx, |editor, cx| {
 3287                            let completions = menu.completions.clone();
 3288                            let matches = menu.matches.clone();
 3289
 3290                            let delay_ms = EditorSettings::get_global(cx)
 3291                                .completion_documentation_secondary_query_debounce;
 3292                            let delay = Duration::from_millis(delay_ms);
 3293
 3294                            editor
 3295                                .completion_documentation_pre_resolve_debounce
 3296                                .fire_new(delay, cx, |editor, cx| {
 3297                                    CompletionsMenu::pre_resolve_completion_documentation(
 3298                                        completions,
 3299                                        matches,
 3300                                        editor,
 3301                                        cx,
 3302                                    )
 3303                                });
 3304                        })
 3305                        .ok();
 3306                        Some(menu)
 3307                    }
 3308                } else {
 3309                    None
 3310                };
 3311
 3312                this.update(&mut cx, |this, cx| {
 3313                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 3314
 3315                    let mut context_menu = this.context_menu.write();
 3316                    match context_menu.as_ref() {
 3317                        None => {}
 3318
 3319                        Some(ContextMenu::Completions(prev_menu)) => {
 3320                            if prev_menu.id > id {
 3321                                return;
 3322                            }
 3323                        }
 3324
 3325                        _ => return,
 3326                    }
 3327
 3328                    if this.focus_handle.is_focused(cx) && menu.is_some() {
 3329                        let menu = menu.unwrap();
 3330                        *context_menu = Some(ContextMenu::Completions(menu));
 3331                        drop(context_menu);
 3332                        this.discard_copilot_suggestion(cx);
 3333                        cx.notify();
 3334                    } else if this.completion_tasks.len() <= 1 {
 3335                        // If there are no more completion tasks and the last menu was
 3336                        // empty, we should hide it. If it was already hidden, we should
 3337                        // also show the copilot suggestion when available.
 3338                        drop(context_menu);
 3339                        if this.hide_context_menu(cx).is_none() {
 3340                            this.update_visible_copilot_suggestion(cx);
 3341                        }
 3342                    }
 3343                })?;
 3344
 3345                Ok::<_, anyhow::Error>(())
 3346            }
 3347            .log_err()
 3348        });
 3349
 3350        self.completion_tasks.push((id, task));
 3351    }
 3352
 3353    pub fn confirm_completion(
 3354        &mut self,
 3355        action: &ConfirmCompletion,
 3356        cx: &mut ViewContext<Self>,
 3357    ) -> Option<Task<Result<()>>> {
 3358        use language::ToOffset as _;
 3359
 3360        let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
 3361            menu
 3362        } else {
 3363            return None;
 3364        };
 3365
 3366        let mat = completions_menu
 3367            .matches
 3368            .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
 3369        let buffer_handle = completions_menu.buffer;
 3370        let completions = completions_menu.completions.read();
 3371        let completion = completions.get(mat.candidate_id)?;
 3372        cx.stop_propagation();
 3373
 3374        let snippet;
 3375        let text;
 3376        if completion.is_snippet() {
 3377            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
 3378            text = snippet.as_ref().unwrap().text.clone();
 3379        } else {
 3380            snippet = None;
 3381            text = completion.new_text.clone();
 3382        };
 3383        let selections = self.selections.all::<usize>(cx);
 3384        let buffer = buffer_handle.read(cx);
 3385        let old_range = completion.old_range.to_offset(buffer);
 3386        let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
 3387
 3388        let newest_selection = self.selections.newest_anchor();
 3389        if newest_selection.start.buffer_id != Some(buffer_handle.read(cx).remote_id()) {
 3390            return None;
 3391        }
 3392
 3393        let lookbehind = newest_selection
 3394            .start
 3395            .text_anchor
 3396            .to_offset(buffer)
 3397            .saturating_sub(old_range.start);
 3398        let lookahead = old_range
 3399            .end
 3400            .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
 3401        let mut common_prefix_len = old_text
 3402            .bytes()
 3403            .zip(text.bytes())
 3404            .take_while(|(a, b)| a == b)
 3405            .count();
 3406
 3407        let snapshot = self.buffer.read(cx).snapshot(cx);
 3408        let mut range_to_replace: Option<Range<isize>> = None;
 3409        let mut ranges = Vec::new();
 3410        for selection in &selections {
 3411            if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
 3412                let start = selection.start.saturating_sub(lookbehind);
 3413                let end = selection.end + lookahead;
 3414                if selection.id == newest_selection.id {
 3415                    range_to_replace = Some(
 3416                        ((start + common_prefix_len) as isize - selection.start as isize)
 3417                            ..(end as isize - selection.start as isize),
 3418                    );
 3419                }
 3420                ranges.push(start + common_prefix_len..end);
 3421            } else {
 3422                common_prefix_len = 0;
 3423                ranges.clear();
 3424                ranges.extend(selections.iter().map(|s| {
 3425                    if s.id == newest_selection.id {
 3426                        range_to_replace = Some(
 3427                            old_range.start.to_offset_utf16(&snapshot).0 as isize
 3428                                - selection.start as isize
 3429                                ..old_range.end.to_offset_utf16(&snapshot).0 as isize
 3430                                    - selection.start as isize,
 3431                        );
 3432                        old_range.clone()
 3433                    } else {
 3434                        s.start..s.end
 3435                    }
 3436                }));
 3437                break;
 3438            }
 3439        }
 3440        let text = &text[common_prefix_len..];
 3441
 3442        cx.emit(EditorEvent::InputHandled {
 3443            utf16_range_to_replace: range_to_replace,
 3444            text: text.into(),
 3445        });
 3446
 3447        self.transact(cx, |this, cx| {
 3448            if let Some(mut snippet) = snippet {
 3449                snippet.text = text.to_string();
 3450                for tabstop in snippet.tabstops.iter_mut().flatten() {
 3451                    tabstop.start -= common_prefix_len as isize;
 3452                    tabstop.end -= common_prefix_len as isize;
 3453                }
 3454
 3455                this.insert_snippet(&ranges, snippet, cx).log_err();
 3456            } else {
 3457                this.buffer.update(cx, |buffer, cx| {
 3458                    buffer.edit(
 3459                        ranges.iter().map(|range| (range.clone(), text)),
 3460                        this.autoindent_mode.clone(),
 3461                        cx,
 3462                    );
 3463                });
 3464            }
 3465
 3466            this.refresh_copilot_suggestions(true, cx);
 3467        });
 3468
 3469        let provider = self.completion_provider.as_ref()?;
 3470        let apply_edits = provider.apply_additional_edits_for_completion(
 3471            buffer_handle,
 3472            completion.clone(),
 3473            true,
 3474            cx,
 3475        );
 3476        Some(cx.foreground_executor().spawn(async move {
 3477            apply_edits.await?;
 3478            Ok(())
 3479        }))
 3480    }
 3481
 3482    pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
 3483        let mut context_menu = self.context_menu.write();
 3484        if matches!(context_menu.as_ref(), Some(ContextMenu::CodeActions(_))) {
 3485            *context_menu = None;
 3486            cx.notify();
 3487            return;
 3488        }
 3489        drop(context_menu);
 3490
 3491        let deployed_from_indicator = action.deployed_from_indicator;
 3492        let mut task = self.code_actions_task.take();
 3493        cx.spawn(|this, mut cx| async move {
 3494            while let Some(prev_task) = task {
 3495                prev_task.await;
 3496                task = this.update(&mut cx, |this, _| this.code_actions_task.take())?;
 3497            }
 3498
 3499            this.update(&mut cx, |this, cx| {
 3500                if this.focus_handle.is_focused(cx) {
 3501                    if let Some((buffer, actions)) = this.available_code_actions.clone() {
 3502                        this.completion_tasks.clear();
 3503                        this.discard_copilot_suggestion(cx);
 3504                        *this.context_menu.write() =
 3505                            Some(ContextMenu::CodeActions(CodeActionsMenu {
 3506                                buffer,
 3507                                actions,
 3508                                selected_item: Default::default(),
 3509                                scroll_handle: UniformListScrollHandle::default(),
 3510                                deployed_from_indicator,
 3511                            }));
 3512                        cx.notify();
 3513                    }
 3514                }
 3515            })?;
 3516
 3517            Ok::<_, anyhow::Error>(())
 3518        })
 3519        .detach_and_log_err(cx);
 3520    }
 3521
 3522    pub fn confirm_code_action(
 3523        &mut self,
 3524        action: &ConfirmCodeAction,
 3525        cx: &mut ViewContext<Self>,
 3526    ) -> Option<Task<Result<()>>> {
 3527        let actions_menu = if let ContextMenu::CodeActions(menu) = self.hide_context_menu(cx)? {
 3528            menu
 3529        } else {
 3530            return None;
 3531        };
 3532        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 3533        let action = actions_menu.actions.get(action_ix)?.clone();
 3534        let title = action.lsp_action.title.clone();
 3535        let buffer = actions_menu.buffer;
 3536        let workspace = self.workspace()?;
 3537
 3538        let apply_code_actions = workspace
 3539            .read(cx)
 3540            .project()
 3541            .clone()
 3542            .update(cx, |project, cx| {
 3543                project.apply_code_action(buffer, action, true, cx)
 3544            });
 3545        let workspace = workspace.downgrade();
 3546        Some(cx.spawn(|editor, cx| async move {
 3547            let project_transaction = apply_code_actions.await?;
 3548            Self::open_project_transaction(&editor, workspace, project_transaction, title, cx).await
 3549        }))
 3550    }
 3551
 3552    async fn open_project_transaction(
 3553        this: &WeakView<Editor>,
 3554        workspace: WeakView<Workspace>,
 3555        transaction: ProjectTransaction,
 3556        title: String,
 3557        mut cx: AsyncWindowContext,
 3558    ) -> Result<()> {
 3559        let replica_id = this.update(&mut cx, |this, cx| this.replica_id(cx))?;
 3560
 3561        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 3562        cx.update(|cx| {
 3563            entries.sort_unstable_by_key(|(buffer, _)| {
 3564                buffer.read(cx).file().map(|f| f.path().clone())
 3565            });
 3566        })?;
 3567
 3568        // If the project transaction's edits are all contained within this editor, then
 3569        // avoid opening a new editor to display them.
 3570
 3571        if let Some((buffer, transaction)) = entries.first() {
 3572            if entries.len() == 1 {
 3573                let excerpt = this.update(&mut cx, |editor, cx| {
 3574                    editor
 3575                        .buffer()
 3576                        .read(cx)
 3577                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 3578                })?;
 3579                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 3580                    if excerpted_buffer == *buffer {
 3581                        let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
 3582                            let excerpt_range = excerpt_range.to_offset(buffer);
 3583                            buffer
 3584                                .edited_ranges_for_transaction::<usize>(transaction)
 3585                                .all(|range| {
 3586                                    excerpt_range.start <= range.start
 3587                                        && excerpt_range.end >= range.end
 3588                                })
 3589                        })?;
 3590
 3591                        if all_edits_within_excerpt {
 3592                            return Ok(());
 3593                        }
 3594                    }
 3595                }
 3596            }
 3597        } else {
 3598            return Ok(());
 3599        }
 3600
 3601        let mut ranges_to_highlight = Vec::new();
 3602        let excerpt_buffer = cx.new_model(|cx| {
 3603            let mut multibuffer =
 3604                MultiBuffer::new(replica_id, Capability::ReadWrite).with_title(title);
 3605            for (buffer_handle, transaction) in &entries {
 3606                let buffer = buffer_handle.read(cx);
 3607                ranges_to_highlight.extend(
 3608                    multibuffer.push_excerpts_with_context_lines(
 3609                        buffer_handle.clone(),
 3610                        buffer
 3611                            .edited_ranges_for_transaction::<usize>(transaction)
 3612                            .collect(),
 3613                        1,
 3614                        cx,
 3615                    ),
 3616                );
 3617            }
 3618            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 3619            multibuffer
 3620        })?;
 3621
 3622        workspace.update(&mut cx, |workspace, cx| {
 3623            let project = workspace.project().clone();
 3624            let editor =
 3625                cx.new_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
 3626            workspace.add_item(Box::new(editor.clone()), cx);
 3627            editor.update(cx, |editor, cx| {
 3628                editor.highlight_background::<Self>(
 3629                    ranges_to_highlight,
 3630                    |theme| theme.editor_highlighted_line_background,
 3631                    cx,
 3632                );
 3633            });
 3634        })?;
 3635
 3636        Ok(())
 3637    }
 3638
 3639    fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
 3640        let project = self.project.clone()?;
 3641        let buffer = self.buffer.read(cx);
 3642        let newest_selection = self.selections.newest_anchor().clone();
 3643        let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
 3644        let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
 3645        if start_buffer != end_buffer {
 3646            return None;
 3647        }
 3648
 3649        self.code_actions_task = Some(cx.spawn(|this, mut cx| async move {
 3650            cx.background_executor()
 3651                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 3652                .await;
 3653
 3654            let actions = if let Ok(code_actions) = project.update(&mut cx, |project, cx| {
 3655                project.code_actions(&start_buffer, start..end, cx)
 3656            }) {
 3657                code_actions.await.log_err()
 3658            } else {
 3659                None
 3660            };
 3661
 3662            this.update(&mut cx, |this, cx| {
 3663                this.available_code_actions = actions.and_then(|actions| {
 3664                    if actions.is_empty() {
 3665                        None
 3666                    } else {
 3667                        Some((start_buffer, actions.into()))
 3668                    }
 3669                });
 3670                cx.notify();
 3671            })
 3672            .log_err();
 3673        }));
 3674        None
 3675    }
 3676
 3677    fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
 3678        if self.pending_rename.is_some() {
 3679            return None;
 3680        }
 3681
 3682        let project = self.project.clone()?;
 3683        let buffer = self.buffer.read(cx);
 3684        let newest_selection = self.selections.newest_anchor().clone();
 3685        let cursor_position = newest_selection.head();
 3686        let (cursor_buffer, cursor_buffer_position) =
 3687            buffer.text_anchor_for_position(cursor_position.clone(), cx)?;
 3688        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 3689        if cursor_buffer != tail_buffer {
 3690            return None;
 3691        }
 3692
 3693        self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move {
 3694            cx.background_executor()
 3695                .timer(DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT)
 3696                .await;
 3697
 3698            let highlights = if let Some(highlights) = project
 3699                .update(&mut cx, |project, cx| {
 3700                    project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 3701                })
 3702                .log_err()
 3703            {
 3704                highlights.await.log_err()
 3705            } else {
 3706                None
 3707            };
 3708
 3709            if let Some(highlights) = highlights {
 3710                this.update(&mut cx, |this, cx| {
 3711                    if this.pending_rename.is_some() {
 3712                        return;
 3713                    }
 3714
 3715                    let buffer_id = cursor_position.buffer_id;
 3716                    let buffer = this.buffer.read(cx);
 3717                    if !buffer
 3718                        .text_anchor_for_position(cursor_position, cx)
 3719                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 3720                    {
 3721                        return;
 3722                    }
 3723
 3724                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 3725                    let mut write_ranges = Vec::new();
 3726                    let mut read_ranges = Vec::new();
 3727                    for highlight in highlights {
 3728                        for (excerpt_id, excerpt_range) in
 3729                            buffer.excerpts_for_buffer(&cursor_buffer, cx)
 3730                        {
 3731                            let start = highlight
 3732                                .range
 3733                                .start
 3734                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 3735                            let end = highlight
 3736                                .range
 3737                                .end
 3738                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 3739                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 3740                                continue;
 3741                            }
 3742
 3743                            let range = Anchor {
 3744                                buffer_id,
 3745                                excerpt_id: excerpt_id.clone(),
 3746                                text_anchor: start,
 3747                            }..Anchor {
 3748                                buffer_id,
 3749                                excerpt_id,
 3750                                text_anchor: end,
 3751                            };
 3752                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 3753                                write_ranges.push(range);
 3754                            } else {
 3755                                read_ranges.push(range);
 3756                            }
 3757                        }
 3758                    }
 3759
 3760                    this.highlight_background::<DocumentHighlightRead>(
 3761                        read_ranges,
 3762                        |theme| theme.editor_document_highlight_read_background,
 3763                        cx,
 3764                    );
 3765                    this.highlight_background::<DocumentHighlightWrite>(
 3766                        write_ranges,
 3767                        |theme| theme.editor_document_highlight_write_background,
 3768                        cx,
 3769                    );
 3770                    cx.notify();
 3771                })
 3772                .log_err();
 3773            }
 3774        }));
 3775        None
 3776    }
 3777
 3778    fn refresh_copilot_suggestions(
 3779        &mut self,
 3780        debounce: bool,
 3781        cx: &mut ViewContext<Self>,
 3782    ) -> Option<()> {
 3783        let copilot = Copilot::global(cx)?;
 3784        if !self.show_copilot_suggestions || !copilot.read(cx).status().is_authorized() {
 3785            self.clear_copilot_suggestions(cx);
 3786            return None;
 3787        }
 3788        self.update_visible_copilot_suggestion(cx);
 3789
 3790        let snapshot = self.buffer.read(cx).snapshot(cx);
 3791        let cursor = self.selections.newest_anchor().head();
 3792        if !self.is_copilot_enabled_at(cursor, &snapshot, cx) {
 3793            self.clear_copilot_suggestions(cx);
 3794            return None;
 3795        }
 3796
 3797        let (buffer, buffer_position) =
 3798            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 3799        self.copilot_state.pending_refresh = cx.spawn(|this, mut cx| async move {
 3800            if debounce {
 3801                cx.background_executor()
 3802                    .timer(COPILOT_DEBOUNCE_TIMEOUT)
 3803                    .await;
 3804            }
 3805
 3806            let completions = copilot
 3807                .update(&mut cx, |copilot, cx| {
 3808                    copilot.completions(&buffer, buffer_position, cx)
 3809                })
 3810                .log_err()
 3811                .unwrap_or(Task::ready(Ok(Vec::new())))
 3812                .await
 3813                .log_err()
 3814                .into_iter()
 3815                .flatten()
 3816                .collect_vec();
 3817
 3818            this.update(&mut cx, |this, cx| {
 3819                if !completions.is_empty() {
 3820                    this.copilot_state.cycled = false;
 3821                    this.copilot_state.pending_cycling_refresh = Task::ready(None);
 3822                    this.copilot_state.completions.clear();
 3823                    this.copilot_state.active_completion_index = 0;
 3824                    this.copilot_state.excerpt_id = Some(cursor.excerpt_id);
 3825                    for completion in completions {
 3826                        this.copilot_state.push_completion(completion);
 3827                    }
 3828                    this.update_visible_copilot_suggestion(cx);
 3829                }
 3830            })
 3831            .log_err()?;
 3832            Some(())
 3833        });
 3834
 3835        Some(())
 3836    }
 3837
 3838    fn cycle_copilot_suggestions(
 3839        &mut self,
 3840        direction: Direction,
 3841        cx: &mut ViewContext<Self>,
 3842    ) -> Option<()> {
 3843        let copilot = Copilot::global(cx)?;
 3844        if !self.show_copilot_suggestions || !copilot.read(cx).status().is_authorized() {
 3845            return None;
 3846        }
 3847
 3848        if self.copilot_state.cycled {
 3849            self.copilot_state.cycle_completions(direction);
 3850            self.update_visible_copilot_suggestion(cx);
 3851        } else {
 3852            let cursor = self.selections.newest_anchor().head();
 3853            let (buffer, buffer_position) =
 3854                self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 3855            self.copilot_state.pending_cycling_refresh = cx.spawn(|this, mut cx| async move {
 3856                let completions = copilot
 3857                    .update(&mut cx, |copilot, cx| {
 3858                        copilot.completions_cycling(&buffer, buffer_position, cx)
 3859                    })
 3860                    .log_err()?
 3861                    .await;
 3862
 3863                this.update(&mut cx, |this, cx| {
 3864                    this.copilot_state.cycled = true;
 3865                    for completion in completions.log_err().into_iter().flatten() {
 3866                        this.copilot_state.push_completion(completion);
 3867                    }
 3868                    this.copilot_state.cycle_completions(direction);
 3869                    this.update_visible_copilot_suggestion(cx);
 3870                })
 3871                .log_err()?;
 3872
 3873                Some(())
 3874            });
 3875        }
 3876
 3877        Some(())
 3878    }
 3879
 3880    fn copilot_suggest(&mut self, _: &copilot::Suggest, cx: &mut ViewContext<Self>) {
 3881        if !self.has_active_copilot_suggestion(cx) {
 3882            self.refresh_copilot_suggestions(false, cx);
 3883            return;
 3884        }
 3885
 3886        self.update_visible_copilot_suggestion(cx);
 3887    }
 3888
 3889    pub fn display_cursor_names(&mut self, _: &DisplayCursorNames, cx: &mut ViewContext<Self>) {
 3890        self.show_cursor_names(cx);
 3891    }
 3892
 3893    fn show_cursor_names(&mut self, cx: &mut ViewContext<Self>) {
 3894        self.show_cursor_names = true;
 3895        cx.notify();
 3896        cx.spawn(|this, mut cx| async move {
 3897            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 3898            this.update(&mut cx, |this, cx| {
 3899                this.show_cursor_names = false;
 3900                cx.notify()
 3901            })
 3902            .ok()
 3903        })
 3904        .detach();
 3905    }
 3906
 3907    fn next_copilot_suggestion(&mut self, _: &copilot::NextSuggestion, cx: &mut ViewContext<Self>) {
 3908        if self.has_active_copilot_suggestion(cx) {
 3909            self.cycle_copilot_suggestions(Direction::Next, cx);
 3910        } else {
 3911            let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none();
 3912            if is_copilot_disabled {
 3913                cx.propagate();
 3914            }
 3915        }
 3916    }
 3917
 3918    fn previous_copilot_suggestion(
 3919        &mut self,
 3920        _: &copilot::PreviousSuggestion,
 3921        cx: &mut ViewContext<Self>,
 3922    ) {
 3923        if self.has_active_copilot_suggestion(cx) {
 3924            self.cycle_copilot_suggestions(Direction::Prev, cx);
 3925        } else {
 3926            let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none();
 3927            if is_copilot_disabled {
 3928                cx.propagate();
 3929            }
 3930        }
 3931    }
 3932
 3933    fn accept_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
 3934        if let Some(suggestion) = self.take_active_copilot_suggestion(cx) {
 3935            if let Some((copilot, completion)) =
 3936                Copilot::global(cx).zip(self.copilot_state.active_completion())
 3937            {
 3938                copilot
 3939                    .update(cx, |copilot, cx| copilot.accept_completion(completion, cx))
 3940                    .detach_and_log_err(cx);
 3941
 3942                self.report_copilot_event(Some(completion.uuid.clone()), true, cx)
 3943            }
 3944            cx.emit(EditorEvent::InputHandled {
 3945                utf16_range_to_replace: None,
 3946                text: suggestion.text.to_string().into(),
 3947            });
 3948            self.insert_with_autoindent_mode(&suggestion.text.to_string(), None, cx);
 3949            cx.notify();
 3950            true
 3951        } else {
 3952            false
 3953        }
 3954    }
 3955
 3956    fn discard_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
 3957        if let Some(suggestion) = self.take_active_copilot_suggestion(cx) {
 3958            if let Some(copilot) = Copilot::global(cx) {
 3959                copilot
 3960                    .update(cx, |copilot, cx| {
 3961                        copilot.discard_completions(&self.copilot_state.completions, cx)
 3962                    })
 3963                    .detach_and_log_err(cx);
 3964
 3965                self.report_copilot_event(None, false, cx)
 3966            }
 3967
 3968            self.display_map.update(cx, |map, cx| {
 3969                map.splice_inlays(vec![suggestion.id], Vec::new(), cx)
 3970            });
 3971            cx.notify();
 3972            true
 3973        } else {
 3974            false
 3975        }
 3976    }
 3977
 3978    fn is_copilot_enabled_at(
 3979        &self,
 3980        location: Anchor,
 3981        snapshot: &MultiBufferSnapshot,
 3982        cx: &mut ViewContext<Self>,
 3983    ) -> bool {
 3984        let file = snapshot.file_at(location);
 3985        let language = snapshot.language_at(location);
 3986        let settings = all_language_settings(file, cx);
 3987        self.show_copilot_suggestions
 3988            && settings.copilot_enabled(language, file.map(|f| f.path().as_ref()))
 3989    }
 3990
 3991    fn has_active_copilot_suggestion(&self, cx: &AppContext) -> bool {
 3992        if let Some(suggestion) = self.copilot_state.suggestion.as_ref() {
 3993            let buffer = self.buffer.read(cx).read(cx);
 3994            suggestion.position.is_valid(&buffer)
 3995        } else {
 3996            false
 3997        }
 3998    }
 3999
 4000    fn take_active_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> Option<Inlay> {
 4001        let suggestion = self.copilot_state.suggestion.take()?;
 4002        self.display_map.update(cx, |map, cx| {
 4003            map.splice_inlays(vec![suggestion.id], Default::default(), cx);
 4004        });
 4005        let buffer = self.buffer.read(cx).read(cx);
 4006
 4007        if suggestion.position.is_valid(&buffer) {
 4008            Some(suggestion)
 4009        } else {
 4010            None
 4011        }
 4012    }
 4013
 4014    fn update_visible_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) {
 4015        let snapshot = self.buffer.read(cx).snapshot(cx);
 4016        let selection = self.selections.newest_anchor();
 4017        let cursor = selection.head();
 4018
 4019        if self.context_menu.read().is_some()
 4020            || !self.completion_tasks.is_empty()
 4021            || selection.start != selection.end
 4022        {
 4023            self.discard_copilot_suggestion(cx);
 4024        } else if let Some(text) = self
 4025            .copilot_state
 4026            .text_for_active_completion(cursor, &snapshot)
 4027        {
 4028            let text = Rope::from(text);
 4029            let mut to_remove = Vec::new();
 4030            if let Some(suggestion) = self.copilot_state.suggestion.take() {
 4031                to_remove.push(suggestion.id);
 4032            }
 4033
 4034            let suggestion_inlay =
 4035                Inlay::suggestion(post_inc(&mut self.next_inlay_id), cursor, text);
 4036            self.copilot_state.suggestion = Some(suggestion_inlay.clone());
 4037            self.display_map.update(cx, move |map, cx| {
 4038                map.splice_inlays(to_remove, vec![suggestion_inlay], cx)
 4039            });
 4040            cx.notify();
 4041        } else {
 4042            self.discard_copilot_suggestion(cx);
 4043        }
 4044    }
 4045
 4046    fn clear_copilot_suggestions(&mut self, cx: &mut ViewContext<Self>) {
 4047        self.copilot_state = Default::default();
 4048        self.discard_copilot_suggestion(cx);
 4049    }
 4050
 4051    pub fn render_code_actions_indicator(
 4052        &self,
 4053        _style: &EditorStyle,
 4054        is_active: bool,
 4055        cx: &mut ViewContext<Self>,
 4056    ) -> Option<IconButton> {
 4057        if self.available_code_actions.is_some() {
 4058            Some(
 4059                IconButton::new("code_actions_indicator", ui::IconName::Bolt)
 4060                    .icon_size(IconSize::Small)
 4061                    .icon_color(Color::Muted)
 4062                    .selected(is_active)
 4063                    .on_click(cx.listener(|editor, _e, cx| {
 4064                        editor.toggle_code_actions(
 4065                            &ToggleCodeActions {
 4066                                deployed_from_indicator: true,
 4067                            },
 4068                            cx,
 4069                        );
 4070                    })),
 4071            )
 4072        } else {
 4073            None
 4074        }
 4075    }
 4076
 4077    pub fn render_fold_indicators(
 4078        &self,
 4079        fold_data: Vec<Option<(FoldStatus, u32, bool)>>,
 4080        _style: &EditorStyle,
 4081        gutter_hovered: bool,
 4082        _line_height: Pixels,
 4083        _gutter_margin: Pixels,
 4084        editor_view: View<Editor>,
 4085    ) -> Vec<Option<IconButton>> {
 4086        fold_data
 4087            .iter()
 4088            .enumerate()
 4089            .map(|(ix, fold_data)| {
 4090                fold_data
 4091                    .map(|(fold_status, buffer_row, active)| {
 4092                        (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
 4093                            IconButton::new(ix as usize, ui::IconName::ChevronDown)
 4094                                .on_click({
 4095                                    let view = editor_view.clone();
 4096                                    move |_e, cx| {
 4097                                        view.update(cx, |editor, cx| match fold_status {
 4098                                            FoldStatus::Folded => {
 4099                                                editor.unfold_at(&UnfoldAt { buffer_row }, cx);
 4100                                            }
 4101                                            FoldStatus::Foldable => {
 4102                                                editor.fold_at(&FoldAt { buffer_row }, cx);
 4103                                            }
 4104                                        })
 4105                                    }
 4106                                })
 4107                                .icon_color(ui::Color::Muted)
 4108                                .icon_size(ui::IconSize::Small)
 4109                                .selected(fold_status == FoldStatus::Folded)
 4110                                .selected_icon(ui::IconName::ChevronRight)
 4111                                .size(ui::ButtonSize::None)
 4112                        })
 4113                    })
 4114                    .flatten()
 4115            })
 4116            .collect()
 4117    }
 4118
 4119    pub fn context_menu_visible(&self) -> bool {
 4120        self.context_menu
 4121            .read()
 4122            .as_ref()
 4123            .map_or(false, |menu| menu.visible())
 4124    }
 4125
 4126    pub fn render_context_menu(
 4127        &self,
 4128        cursor_position: DisplayPoint,
 4129        style: &EditorStyle,
 4130        max_height: Pixels,
 4131        cx: &mut ViewContext<Editor>,
 4132    ) -> Option<(DisplayPoint, AnyElement)> {
 4133        self.context_menu.read().as_ref().map(|menu| {
 4134            menu.render(
 4135                cursor_position,
 4136                style,
 4137                max_height,
 4138                self.workspace.as_ref().map(|(w, _)| w.clone()),
 4139                cx,
 4140            )
 4141        })
 4142    }
 4143
 4144    fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
 4145        cx.notify();
 4146        self.completion_tasks.clear();
 4147        let context_menu = self.context_menu.write().take();
 4148        if context_menu.is_some() {
 4149            self.update_visible_copilot_suggestion(cx);
 4150        }
 4151        context_menu
 4152    }
 4153
 4154    pub fn insert_snippet(
 4155        &mut self,
 4156        insertion_ranges: &[Range<usize>],
 4157        snippet: Snippet,
 4158        cx: &mut ViewContext<Self>,
 4159    ) -> Result<()> {
 4160        let tabstops = self.buffer.update(cx, |buffer, cx| {
 4161            let snippet_text: Arc<str> = snippet.text.clone().into();
 4162            buffer.edit(
 4163                insertion_ranges
 4164                    .iter()
 4165                    .cloned()
 4166                    .map(|range| (range, snippet_text.clone())),
 4167                Some(AutoindentMode::EachLine),
 4168                cx,
 4169            );
 4170
 4171            let snapshot = &*buffer.read(cx);
 4172            let snippet = &snippet;
 4173            snippet
 4174                .tabstops
 4175                .iter()
 4176                .map(|tabstop| {
 4177                    let mut tabstop_ranges = tabstop
 4178                        .iter()
 4179                        .flat_map(|tabstop_range| {
 4180                            let mut delta = 0_isize;
 4181                            insertion_ranges.iter().map(move |insertion_range| {
 4182                                let insertion_start = insertion_range.start as isize + delta;
 4183                                delta +=
 4184                                    snippet.text.len() as isize - insertion_range.len() as isize;
 4185
 4186                                let start = snapshot.anchor_before(
 4187                                    (insertion_start + tabstop_range.start) as usize,
 4188                                );
 4189                                let end = snapshot
 4190                                    .anchor_after((insertion_start + tabstop_range.end) as usize);
 4191                                start..end
 4192                            })
 4193                        })
 4194                        .collect::<Vec<_>>();
 4195                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 4196                    tabstop_ranges
 4197                })
 4198                .collect::<Vec<_>>()
 4199        });
 4200
 4201        if let Some(tabstop) = tabstops.first() {
 4202            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 4203                s.select_ranges(tabstop.iter().cloned());
 4204            });
 4205            self.snippet_stack.push(SnippetState {
 4206                active_index: 0,
 4207                ranges: tabstops,
 4208            });
 4209
 4210            // Check whether the just-entered snippet ends with an auto-closable bracket.
 4211            if self.autoclose_regions.is_empty() {
 4212                let snapshot = self.buffer.read(cx).snapshot(cx);
 4213                for selection in &mut self.selections.all::<Point>(cx) {
 4214                    let selection_head = selection.head();
 4215                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 4216                        continue;
 4217                    };
 4218
 4219                    let mut bracket_pair = None;
 4220                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 4221                    let prev_chars = snapshot
 4222                        .reversed_chars_at(selection_head)
 4223                        .collect::<String>();
 4224                    for (pair, enabled) in scope.brackets() {
 4225                        if enabled
 4226                            && pair.close
 4227                            && prev_chars.starts_with(pair.start.as_str())
 4228                            && next_chars.starts_with(pair.end.as_str())
 4229                        {
 4230                            bracket_pair = Some(pair.clone());
 4231                            break;
 4232                        }
 4233                    }
 4234                    if let Some(pair) = bracket_pair {
 4235                        let start = snapshot.anchor_after(selection_head);
 4236                        let end = snapshot.anchor_after(selection_head);
 4237                        self.autoclose_regions.push(AutocloseRegion {
 4238                            selection_id: selection.id,
 4239                            range: start..end,
 4240                            pair,
 4241                        });
 4242                    }
 4243                }
 4244            }
 4245        }
 4246        Ok(())
 4247    }
 4248
 4249    pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
 4250        self.move_to_snippet_tabstop(Bias::Right, cx)
 4251    }
 4252
 4253    pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
 4254        self.move_to_snippet_tabstop(Bias::Left, cx)
 4255    }
 4256
 4257    pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
 4258        if let Some(mut snippet) = self.snippet_stack.pop() {
 4259            match bias {
 4260                Bias::Left => {
 4261                    if snippet.active_index > 0 {
 4262                        snippet.active_index -= 1;
 4263                    } else {
 4264                        self.snippet_stack.push(snippet);
 4265                        return false;
 4266                    }
 4267                }
 4268                Bias::Right => {
 4269                    if snippet.active_index + 1 < snippet.ranges.len() {
 4270                        snippet.active_index += 1;
 4271                    } else {
 4272                        self.snippet_stack.push(snippet);
 4273                        return false;
 4274                    }
 4275                }
 4276            }
 4277            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 4278                self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 4279                    s.select_anchor_ranges(current_ranges.iter().cloned())
 4280                });
 4281                // If snippet state is not at the last tabstop, push it back on the stack
 4282                if snippet.active_index + 1 < snippet.ranges.len() {
 4283                    self.snippet_stack.push(snippet);
 4284                }
 4285                return true;
 4286            }
 4287        }
 4288
 4289        false
 4290    }
 4291
 4292    pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
 4293        self.transact(cx, |this, cx| {
 4294            this.select_all(&SelectAll, cx);
 4295            this.insert("", cx);
 4296        });
 4297    }
 4298
 4299    pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
 4300        self.transact(cx, |this, cx| {
 4301            this.select_autoclose_pair(cx);
 4302            let mut selections = this.selections.all::<Point>(cx);
 4303            if !this.selections.line_mode {
 4304                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4305                for selection in &mut selections {
 4306                    if selection.is_empty() {
 4307                        let old_head = selection.head();
 4308                        let mut new_head =
 4309                            movement::left(&display_map, old_head.to_display_point(&display_map))
 4310                                .to_point(&display_map);
 4311                        if let Some((buffer, line_buffer_range)) = display_map
 4312                            .buffer_snapshot
 4313                            .buffer_line_for_row(old_head.row)
 4314                        {
 4315                            let indent_size =
 4316                                buffer.indent_size_for_line(line_buffer_range.start.row);
 4317                            let indent_len = match indent_size.kind {
 4318                                IndentKind::Space => {
 4319                                    buffer.settings_at(line_buffer_range.start, cx).tab_size
 4320                                }
 4321                                IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 4322                            };
 4323                            if old_head.column <= indent_size.len && old_head.column > 0 {
 4324                                let indent_len = indent_len.get();
 4325                                new_head = cmp::min(
 4326                                    new_head,
 4327                                    Point::new(
 4328                                        old_head.row,
 4329                                        ((old_head.column - 1) / indent_len) * indent_len,
 4330                                    ),
 4331                                );
 4332                            }
 4333                        }
 4334
 4335                        selection.set_head(new_head, SelectionGoal::None);
 4336                    }
 4337                }
 4338            }
 4339
 4340            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 4341            this.insert("", cx);
 4342            this.refresh_copilot_suggestions(true, cx);
 4343        });
 4344    }
 4345
 4346    pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
 4347        self.transact(cx, |this, cx| {
 4348            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 4349                let line_mode = s.line_mode;
 4350                s.move_with(|map, selection| {
 4351                    if selection.is_empty() && !line_mode {
 4352                        let cursor = movement::right(map, selection.head());
 4353                        selection.end = cursor;
 4354                        selection.reversed = true;
 4355                        selection.goal = SelectionGoal::None;
 4356                    }
 4357                })
 4358            });
 4359            this.insert("", cx);
 4360            this.refresh_copilot_suggestions(true, cx);
 4361        });
 4362    }
 4363
 4364    pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
 4365        if self.move_to_prev_snippet_tabstop(cx) {
 4366            return;
 4367        }
 4368
 4369        self.outdent(&Outdent, cx);
 4370    }
 4371
 4372    pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
 4373        if self.move_to_next_snippet_tabstop(cx) || self.read_only(cx) {
 4374            return;
 4375        }
 4376
 4377        let mut selections = self.selections.all_adjusted(cx);
 4378        let buffer = self.buffer.read(cx);
 4379        let snapshot = buffer.snapshot(cx);
 4380        let rows_iter = selections.iter().map(|s| s.head().row);
 4381        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 4382
 4383        let mut edits = Vec::new();
 4384        let mut prev_edited_row = 0;
 4385        let mut row_delta = 0;
 4386        for selection in &mut selections {
 4387            if selection.start.row != prev_edited_row {
 4388                row_delta = 0;
 4389            }
 4390            prev_edited_row = selection.end.row;
 4391
 4392            // If the selection is non-empty, then increase the indentation of the selected lines.
 4393            if !selection.is_empty() {
 4394                row_delta =
 4395                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 4396                continue;
 4397            }
 4398
 4399            // If the selection is empty and the cursor is in the leading whitespace before the
 4400            // suggested indentation, then auto-indent the line.
 4401            let cursor = selection.head();
 4402            let current_indent = snapshot.indent_size_for_line(cursor.row);
 4403            if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
 4404                if cursor.column < suggested_indent.len
 4405                    && cursor.column <= current_indent.len
 4406                    && current_indent.len <= suggested_indent.len
 4407                {
 4408                    selection.start = Point::new(cursor.row, suggested_indent.len);
 4409                    selection.end = selection.start;
 4410                    if row_delta == 0 {
 4411                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 4412                            cursor.row,
 4413                            current_indent,
 4414                            suggested_indent,
 4415                        ));
 4416                        row_delta = suggested_indent.len - current_indent.len;
 4417                    }
 4418                    continue;
 4419                }
 4420            }
 4421
 4422            // Accept copilot suggestion if there is only one selection and the cursor is not
 4423            // in the leading whitespace.
 4424            if self.selections.count() == 1
 4425                && cursor.column >= current_indent.len
 4426                && self.has_active_copilot_suggestion(cx)
 4427            {
 4428                self.accept_copilot_suggestion(cx);
 4429                return;
 4430            }
 4431
 4432            // Otherwise, insert a hard or soft tab.
 4433            let settings = buffer.settings_at(cursor, cx);
 4434            let tab_size = if settings.hard_tabs {
 4435                IndentSize::tab()
 4436            } else {
 4437                let tab_size = settings.tab_size.get();
 4438                let char_column = snapshot
 4439                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 4440                    .flat_map(str::chars)
 4441                    .count()
 4442                    + row_delta as usize;
 4443                let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
 4444                IndentSize::spaces(chars_to_next_tab_stop)
 4445            };
 4446            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 4447            selection.end = selection.start;
 4448            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 4449            row_delta += tab_size.len;
 4450        }
 4451
 4452        self.transact(cx, |this, cx| {
 4453            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 4454            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 4455            this.refresh_copilot_suggestions(true, cx);
 4456        });
 4457    }
 4458
 4459    pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
 4460        let mut selections = self.selections.all::<Point>(cx);
 4461        let mut prev_edited_row = 0;
 4462        let mut row_delta = 0;
 4463        let mut edits = Vec::new();
 4464        let buffer = self.buffer.read(cx);
 4465        let snapshot = buffer.snapshot(cx);
 4466        for selection in &mut selections {
 4467            if selection.start.row != prev_edited_row {
 4468                row_delta = 0;
 4469            }
 4470            prev_edited_row = selection.end.row;
 4471
 4472            row_delta =
 4473                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 4474        }
 4475
 4476        self.transact(cx, |this, cx| {
 4477            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 4478            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 4479        });
 4480    }
 4481
 4482    fn indent_selection(
 4483        buffer: &MultiBuffer,
 4484        snapshot: &MultiBufferSnapshot,
 4485        selection: &mut Selection<Point>,
 4486        edits: &mut Vec<(Range<Point>, String)>,
 4487        delta_for_start_row: u32,
 4488        cx: &AppContext,
 4489    ) -> u32 {
 4490        let settings = buffer.settings_at(selection.start, cx);
 4491        let tab_size = settings.tab_size.get();
 4492        let indent_kind = if settings.hard_tabs {
 4493            IndentKind::Tab
 4494        } else {
 4495            IndentKind::Space
 4496        };
 4497        let mut start_row = selection.start.row;
 4498        let mut end_row = selection.end.row + 1;
 4499
 4500        // If a selection ends at the beginning of a line, don't indent
 4501        // that last line.
 4502        if selection.end.column == 0 {
 4503            end_row -= 1;
 4504        }
 4505
 4506        // Avoid re-indenting a row that has already been indented by a
 4507        // previous selection, but still update this selection's column
 4508        // to reflect that indentation.
 4509        if delta_for_start_row > 0 {
 4510            start_row += 1;
 4511            selection.start.column += delta_for_start_row;
 4512            if selection.end.row == selection.start.row {
 4513                selection.end.column += delta_for_start_row;
 4514            }
 4515        }
 4516
 4517        let mut delta_for_end_row = 0;
 4518        for row in start_row..end_row {
 4519            let current_indent = snapshot.indent_size_for_line(row);
 4520            let indent_delta = match (current_indent.kind, indent_kind) {
 4521                (IndentKind::Space, IndentKind::Space) => {
 4522                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 4523                    IndentSize::spaces(columns_to_next_tab_stop)
 4524                }
 4525                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 4526                (_, IndentKind::Tab) => IndentSize::tab(),
 4527            };
 4528
 4529            let row_start = Point::new(row, 0);
 4530            edits.push((
 4531                row_start..row_start,
 4532                indent_delta.chars().collect::<String>(),
 4533            ));
 4534
 4535            // Update this selection's endpoints to reflect the indentation.
 4536            if row == selection.start.row {
 4537                selection.start.column += indent_delta.len;
 4538            }
 4539            if row == selection.end.row {
 4540                selection.end.column += indent_delta.len;
 4541                delta_for_end_row = indent_delta.len;
 4542            }
 4543        }
 4544
 4545        if selection.start.row == selection.end.row {
 4546            delta_for_start_row + delta_for_end_row
 4547        } else {
 4548            delta_for_end_row
 4549        }
 4550    }
 4551
 4552    pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
 4553        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4554        let selections = self.selections.all::<Point>(cx);
 4555        let mut deletion_ranges = Vec::new();
 4556        let mut last_outdent = None;
 4557        {
 4558            let buffer = self.buffer.read(cx);
 4559            let snapshot = buffer.snapshot(cx);
 4560            for selection in &selections {
 4561                let settings = buffer.settings_at(selection.start, cx);
 4562                let tab_size = settings.tab_size.get();
 4563                let mut rows = selection.spanned_rows(false, &display_map);
 4564
 4565                // Avoid re-outdenting a row that has already been outdented by a
 4566                // previous selection.
 4567                if let Some(last_row) = last_outdent {
 4568                    if last_row == rows.start {
 4569                        rows.start += 1;
 4570                    }
 4571                }
 4572
 4573                for row in rows {
 4574                    let indent_size = snapshot.indent_size_for_line(row);
 4575                    if indent_size.len > 0 {
 4576                        let deletion_len = match indent_size.kind {
 4577                            IndentKind::Space => {
 4578                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 4579                                if columns_to_prev_tab_stop == 0 {
 4580                                    tab_size
 4581                                } else {
 4582                                    columns_to_prev_tab_stop
 4583                                }
 4584                            }
 4585                            IndentKind::Tab => 1,
 4586                        };
 4587                        deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
 4588                        last_outdent = Some(row);
 4589                    }
 4590                }
 4591            }
 4592        }
 4593
 4594        self.transact(cx, |this, cx| {
 4595            this.buffer.update(cx, |buffer, cx| {
 4596                let empty_str: Arc<str> = "".into();
 4597                buffer.edit(
 4598                    deletion_ranges
 4599                        .into_iter()
 4600                        .map(|range| (range, empty_str.clone())),
 4601                    None,
 4602                    cx,
 4603                );
 4604            });
 4605            let selections = this.selections.all::<usize>(cx);
 4606            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 4607        });
 4608    }
 4609
 4610    pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
 4611        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4612        let selections = self.selections.all::<Point>(cx);
 4613
 4614        let mut new_cursors = Vec::new();
 4615        let mut edit_ranges = Vec::new();
 4616        let mut selections = selections.iter().peekable();
 4617        while let Some(selection) = selections.next() {
 4618            let mut rows = selection.spanned_rows(false, &display_map);
 4619            let goal_display_column = selection.head().to_display_point(&display_map).column();
 4620
 4621            // Accumulate contiguous regions of rows that we want to delete.
 4622            while let Some(next_selection) = selections.peek() {
 4623                let next_rows = next_selection.spanned_rows(false, &display_map);
 4624                if next_rows.start <= rows.end {
 4625                    rows.end = next_rows.end;
 4626                    selections.next().unwrap();
 4627                } else {
 4628                    break;
 4629                }
 4630            }
 4631
 4632            let buffer = &display_map.buffer_snapshot;
 4633            let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
 4634            let edit_end;
 4635            let cursor_buffer_row;
 4636            if buffer.max_point().row >= rows.end {
 4637                // If there's a line after the range, delete the \n from the end of the row range
 4638                // and position the cursor on the next line.
 4639                edit_end = Point::new(rows.end, 0).to_offset(buffer);
 4640                cursor_buffer_row = rows.end;
 4641            } else {
 4642                // If there isn't a line after the range, delete the \n from the line before the
 4643                // start of the row range and position the cursor there.
 4644                edit_start = edit_start.saturating_sub(1);
 4645                edit_end = buffer.len();
 4646                cursor_buffer_row = rows.start.saturating_sub(1);
 4647            }
 4648
 4649            let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
 4650            *cursor.column_mut() =
 4651                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 4652
 4653            new_cursors.push((
 4654                selection.id,
 4655                buffer.anchor_after(cursor.to_point(&display_map)),
 4656            ));
 4657            edit_ranges.push(edit_start..edit_end);
 4658        }
 4659
 4660        self.transact(cx, |this, cx| {
 4661            let buffer = this.buffer.update(cx, |buffer, cx| {
 4662                let empty_str: Arc<str> = "".into();
 4663                buffer.edit(
 4664                    edit_ranges
 4665                        .into_iter()
 4666                        .map(|range| (range, empty_str.clone())),
 4667                    None,
 4668                    cx,
 4669                );
 4670                buffer.snapshot(cx)
 4671            });
 4672            let new_selections = new_cursors
 4673                .into_iter()
 4674                .map(|(id, cursor)| {
 4675                    let cursor = cursor.to_point(&buffer);
 4676                    Selection {
 4677                        id,
 4678                        start: cursor,
 4679                        end: cursor,
 4680                        reversed: false,
 4681                        goal: SelectionGoal::None,
 4682                    }
 4683                })
 4684                .collect();
 4685
 4686            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 4687                s.select(new_selections);
 4688            });
 4689        });
 4690    }
 4691
 4692    pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext<Self>) {
 4693        let mut row_ranges = Vec::<Range<u32>>::new();
 4694        for selection in self.selections.all::<Point>(cx) {
 4695            let start = selection.start.row;
 4696            let end = if selection.start.row == selection.end.row {
 4697                selection.start.row + 1
 4698            } else {
 4699                selection.end.row
 4700            };
 4701
 4702            if let Some(last_row_range) = row_ranges.last_mut() {
 4703                if start <= last_row_range.end {
 4704                    last_row_range.end = end;
 4705                    continue;
 4706                }
 4707            }
 4708            row_ranges.push(start..end);
 4709        }
 4710
 4711        let snapshot = self.buffer.read(cx).snapshot(cx);
 4712        let mut cursor_positions = Vec::new();
 4713        for row_range in &row_ranges {
 4714            let anchor = snapshot.anchor_before(Point::new(
 4715                row_range.end - 1,
 4716                snapshot.line_len(row_range.end - 1),
 4717            ));
 4718            cursor_positions.push(anchor.clone()..anchor);
 4719        }
 4720
 4721        self.transact(cx, |this, cx| {
 4722            for row_range in row_ranges.into_iter().rev() {
 4723                for row in row_range.rev() {
 4724                    let end_of_line = Point::new(row, snapshot.line_len(row));
 4725                    let indent = snapshot.indent_size_for_line(row + 1);
 4726                    let start_of_next_line = Point::new(row + 1, indent.len);
 4727
 4728                    let replace = if snapshot.line_len(row + 1) > indent.len {
 4729                        " "
 4730                    } else {
 4731                        ""
 4732                    };
 4733
 4734                    this.buffer.update(cx, |buffer, cx| {
 4735                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 4736                    });
 4737                }
 4738            }
 4739
 4740            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 4741                s.select_anchor_ranges(cursor_positions)
 4742            });
 4743        });
 4744    }
 4745
 4746    pub fn sort_lines_case_sensitive(
 4747        &mut self,
 4748        _: &SortLinesCaseSensitive,
 4749        cx: &mut ViewContext<Self>,
 4750    ) {
 4751        self.manipulate_lines(cx, |lines| lines.sort())
 4752    }
 4753
 4754    pub fn sort_lines_case_insensitive(
 4755        &mut self,
 4756        _: &SortLinesCaseInsensitive,
 4757        cx: &mut ViewContext<Self>,
 4758    ) {
 4759        self.manipulate_lines(cx, |lines| lines.sort_by_key(|line| line.to_lowercase()))
 4760    }
 4761
 4762    pub fn unique_lines_case_insensitive(
 4763        &mut self,
 4764        _: &UniqueLinesCaseInsensitive,
 4765        cx: &mut ViewContext<Self>,
 4766    ) {
 4767        self.manipulate_lines(cx, |lines| {
 4768            let mut seen = HashSet::default();
 4769            lines.retain(|line| seen.insert(line.to_lowercase()));
 4770        })
 4771    }
 4772
 4773    pub fn unique_lines_case_sensitive(
 4774        &mut self,
 4775        _: &UniqueLinesCaseSensitive,
 4776        cx: &mut ViewContext<Self>,
 4777    ) {
 4778        self.manipulate_lines(cx, |lines| {
 4779            let mut seen = HashSet::default();
 4780            lines.retain(|line| seen.insert(*line));
 4781        })
 4782    }
 4783
 4784    pub fn reverse_lines(&mut self, _: &ReverseLines, cx: &mut ViewContext<Self>) {
 4785        self.manipulate_lines(cx, |lines| lines.reverse())
 4786    }
 4787
 4788    pub fn shuffle_lines(&mut self, _: &ShuffleLines, cx: &mut ViewContext<Self>) {
 4789        self.manipulate_lines(cx, |lines| lines.shuffle(&mut thread_rng()))
 4790    }
 4791
 4792    fn manipulate_lines<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
 4793    where
 4794        Fn: FnMut(&mut Vec<&str>),
 4795    {
 4796        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4797        let buffer = self.buffer.read(cx).snapshot(cx);
 4798
 4799        let mut edits = Vec::new();
 4800
 4801        let selections = self.selections.all::<Point>(cx);
 4802        let mut selections = selections.iter().peekable();
 4803        let mut contiguous_row_selections = Vec::new();
 4804        let mut new_selections = Vec::new();
 4805        let mut added_lines = 0;
 4806        let mut removed_lines = 0;
 4807
 4808        while let Some(selection) = selections.next() {
 4809            let (start_row, end_row) = consume_contiguous_rows(
 4810                &mut contiguous_row_selections,
 4811                selection,
 4812                &display_map,
 4813                &mut selections,
 4814            );
 4815
 4816            let start_point = Point::new(start_row, 0);
 4817            let end_point = Point::new(end_row - 1, buffer.line_len(end_row - 1));
 4818            let text = buffer
 4819                .text_for_range(start_point..end_point)
 4820                .collect::<String>();
 4821
 4822            let mut lines = text.split("\n").collect_vec();
 4823
 4824            let lines_before = lines.len();
 4825            callback(&mut lines);
 4826            let lines_after = lines.len();
 4827
 4828            edits.push((start_point..end_point, lines.join("\n")));
 4829
 4830            // Selections must change based on added and removed line count
 4831            let start_row = start_point.row + added_lines as u32 - removed_lines as u32;
 4832            let end_row = start_row + lines_after.saturating_sub(1) as u32;
 4833            new_selections.push(Selection {
 4834                id: selection.id,
 4835                start: start_row,
 4836                end: end_row,
 4837                goal: SelectionGoal::None,
 4838                reversed: selection.reversed,
 4839            });
 4840
 4841            if lines_after > lines_before {
 4842                added_lines += lines_after - lines_before;
 4843            } else if lines_before > lines_after {
 4844                removed_lines += lines_before - lines_after;
 4845            }
 4846        }
 4847
 4848        self.transact(cx, |this, cx| {
 4849            let buffer = this.buffer.update(cx, |buffer, cx| {
 4850                buffer.edit(edits, None, cx);
 4851                buffer.snapshot(cx)
 4852            });
 4853
 4854            // Recalculate offsets on newly edited buffer
 4855            let new_selections = new_selections
 4856                .iter()
 4857                .map(|s| {
 4858                    let start_point = Point::new(s.start, 0);
 4859                    let end_point = Point::new(s.end, buffer.line_len(s.end));
 4860                    Selection {
 4861                        id: s.id,
 4862                        start: buffer.point_to_offset(start_point),
 4863                        end: buffer.point_to_offset(end_point),
 4864                        goal: s.goal,
 4865                        reversed: s.reversed,
 4866                    }
 4867                })
 4868                .collect();
 4869
 4870            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 4871                s.select(new_selections);
 4872            });
 4873
 4874            this.request_autoscroll(Autoscroll::fit(), cx);
 4875        });
 4876    }
 4877
 4878    pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext<Self>) {
 4879        self.manipulate_text(cx, |text| text.to_uppercase())
 4880    }
 4881
 4882    pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext<Self>) {
 4883        self.manipulate_text(cx, |text| text.to_lowercase())
 4884    }
 4885
 4886    pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext<Self>) {
 4887        self.manipulate_text(cx, |text| {
 4888            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
 4889            // https://github.com/rutrum/convert-case/issues/16
 4890            text.split("\n")
 4891                .map(|line| line.to_case(Case::Title))
 4892                .join("\n")
 4893        })
 4894    }
 4895
 4896    pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext<Self>) {
 4897        self.manipulate_text(cx, |text| text.to_case(Case::Snake))
 4898    }
 4899
 4900    pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext<Self>) {
 4901        self.manipulate_text(cx, |text| text.to_case(Case::Kebab))
 4902    }
 4903
 4904    pub fn convert_to_upper_camel_case(
 4905        &mut self,
 4906        _: &ConvertToUpperCamelCase,
 4907        cx: &mut ViewContext<Self>,
 4908    ) {
 4909        self.manipulate_text(cx, |text| {
 4910            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
 4911            // https://github.com/rutrum/convert-case/issues/16
 4912            text.split("\n")
 4913                .map(|line| line.to_case(Case::UpperCamel))
 4914                .join("\n")
 4915        })
 4916    }
 4917
 4918    pub fn convert_to_lower_camel_case(
 4919        &mut self,
 4920        _: &ConvertToLowerCamelCase,
 4921        cx: &mut ViewContext<Self>,
 4922    ) {
 4923        self.manipulate_text(cx, |text| text.to_case(Case::Camel))
 4924    }
 4925
 4926    fn manipulate_text<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
 4927    where
 4928        Fn: FnMut(&str) -> String,
 4929    {
 4930        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4931        let buffer = self.buffer.read(cx).snapshot(cx);
 4932
 4933        let mut new_selections = Vec::new();
 4934        let mut edits = Vec::new();
 4935        let mut selection_adjustment = 0i32;
 4936
 4937        for selection in self.selections.all::<usize>(cx) {
 4938            let selection_is_empty = selection.is_empty();
 4939
 4940            let (start, end) = if selection_is_empty {
 4941                let word_range = movement::surrounding_word(
 4942                    &display_map,
 4943                    selection.start.to_display_point(&display_map),
 4944                );
 4945                let start = word_range.start.to_offset(&display_map, Bias::Left);
 4946                let end = word_range.end.to_offset(&display_map, Bias::Left);
 4947                (start, end)
 4948            } else {
 4949                (selection.start, selection.end)
 4950            };
 4951
 4952            let text = buffer.text_for_range(start..end).collect::<String>();
 4953            let old_length = text.len() as i32;
 4954            let text = callback(&text);
 4955
 4956            new_selections.push(Selection {
 4957                start: (start as i32 - selection_adjustment) as usize,
 4958                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
 4959                goal: SelectionGoal::None,
 4960                ..selection
 4961            });
 4962
 4963            selection_adjustment += old_length - text.len() as i32;
 4964
 4965            edits.push((start..end, text));
 4966        }
 4967
 4968        self.transact(cx, |this, cx| {
 4969            this.buffer.update(cx, |buffer, cx| {
 4970                buffer.edit(edits, None, cx);
 4971            });
 4972
 4973            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 4974                s.select(new_selections);
 4975            });
 4976
 4977            this.request_autoscroll(Autoscroll::fit(), cx);
 4978        });
 4979    }
 4980
 4981    pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
 4982        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4983        let buffer = &display_map.buffer_snapshot;
 4984        let selections = self.selections.all::<Point>(cx);
 4985
 4986        let mut edits = Vec::new();
 4987        let mut selections_iter = selections.iter().peekable();
 4988        while let Some(selection) = selections_iter.next() {
 4989            // Avoid duplicating the same lines twice.
 4990            let mut rows = selection.spanned_rows(false, &display_map);
 4991
 4992            while let Some(next_selection) = selections_iter.peek() {
 4993                let next_rows = next_selection.spanned_rows(false, &display_map);
 4994                if next_rows.start < rows.end {
 4995                    rows.end = next_rows.end;
 4996                    selections_iter.next().unwrap();
 4997                } else {
 4998                    break;
 4999                }
 5000            }
 5001
 5002            // Copy the text from the selected row region and splice it at the start of the region.
 5003            let start = Point::new(rows.start, 0);
 5004            let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
 5005            let text = buffer
 5006                .text_for_range(start..end)
 5007                .chain(Some("\n"))
 5008                .collect::<String>();
 5009            edits.push((start..start, text));
 5010        }
 5011
 5012        self.transact(cx, |this, cx| {
 5013            this.buffer.update(cx, |buffer, cx| {
 5014                buffer.edit(edits, None, cx);
 5015            });
 5016
 5017            this.request_autoscroll(Autoscroll::fit(), cx);
 5018        });
 5019    }
 5020
 5021    pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
 5022        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5023        let buffer = self.buffer.read(cx).snapshot(cx);
 5024
 5025        let mut edits = Vec::new();
 5026        let mut unfold_ranges = Vec::new();
 5027        let mut refold_ranges = Vec::new();
 5028
 5029        let selections = self.selections.all::<Point>(cx);
 5030        let mut selections = selections.iter().peekable();
 5031        let mut contiguous_row_selections = Vec::new();
 5032        let mut new_selections = Vec::new();
 5033
 5034        while let Some(selection) = selections.next() {
 5035            // Find all the selections that span a contiguous row range
 5036            let (start_row, end_row) = consume_contiguous_rows(
 5037                &mut contiguous_row_selections,
 5038                selection,
 5039                &display_map,
 5040                &mut selections,
 5041            );
 5042
 5043            // Move the text spanned by the row range to be before the line preceding the row range
 5044            if start_row > 0 {
 5045                let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
 5046                    ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
 5047                let insertion_point = display_map
 5048                    .prev_line_boundary(Point::new(start_row - 1, 0))
 5049                    .0;
 5050
 5051                // Don't move lines across excerpts
 5052                if buffer
 5053                    .excerpt_boundaries_in_range((
 5054                        Bound::Excluded(insertion_point),
 5055                        Bound::Included(range_to_move.end),
 5056                    ))
 5057                    .next()
 5058                    .is_none()
 5059                {
 5060                    let text = buffer
 5061                        .text_for_range(range_to_move.clone())
 5062                        .flat_map(|s| s.chars())
 5063                        .skip(1)
 5064                        .chain(['\n'])
 5065                        .collect::<String>();
 5066
 5067                    edits.push((
 5068                        buffer.anchor_after(range_to_move.start)
 5069                            ..buffer.anchor_before(range_to_move.end),
 5070                        String::new(),
 5071                    ));
 5072                    let insertion_anchor = buffer.anchor_after(insertion_point);
 5073                    edits.push((insertion_anchor..insertion_anchor, text));
 5074
 5075                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
 5076
 5077                    // Move selections up
 5078                    new_selections.extend(contiguous_row_selections.drain(..).map(
 5079                        |mut selection| {
 5080                            selection.start.row -= row_delta;
 5081                            selection.end.row -= row_delta;
 5082                            selection
 5083                        },
 5084                    ));
 5085
 5086                    // Move folds up
 5087                    unfold_ranges.push(range_to_move.clone());
 5088                    for fold in display_map.folds_in_range(
 5089                        buffer.anchor_before(range_to_move.start)
 5090                            ..buffer.anchor_after(range_to_move.end),
 5091                    ) {
 5092                        let mut start = fold.range.start.to_point(&buffer);
 5093                        let mut end = fold.range.end.to_point(&buffer);
 5094                        start.row -= row_delta;
 5095                        end.row -= row_delta;
 5096                        refold_ranges.push(start..end);
 5097                    }
 5098                }
 5099            }
 5100
 5101            // If we didn't move line(s), preserve the existing selections
 5102            new_selections.append(&mut contiguous_row_selections);
 5103        }
 5104
 5105        self.transact(cx, |this, cx| {
 5106            this.unfold_ranges(unfold_ranges, true, true, cx);
 5107            this.buffer.update(cx, |buffer, cx| {
 5108                for (range, text) in edits {
 5109                    buffer.edit([(range, text)], None, cx);
 5110                }
 5111            });
 5112            this.fold_ranges(refold_ranges, true, cx);
 5113            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5114                s.select(new_selections);
 5115            })
 5116        });
 5117    }
 5118
 5119    pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
 5120        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5121        let buffer = self.buffer.read(cx).snapshot(cx);
 5122
 5123        let mut edits = Vec::new();
 5124        let mut unfold_ranges = Vec::new();
 5125        let mut refold_ranges = Vec::new();
 5126
 5127        let selections = self.selections.all::<Point>(cx);
 5128        let mut selections = selections.iter().peekable();
 5129        let mut contiguous_row_selections = Vec::new();
 5130        let mut new_selections = Vec::new();
 5131
 5132        while let Some(selection) = selections.next() {
 5133            // Find all the selections that span a contiguous row range
 5134            let (start_row, end_row) = consume_contiguous_rows(
 5135                &mut contiguous_row_selections,
 5136                selection,
 5137                &display_map,
 5138                &mut selections,
 5139            );
 5140
 5141            // Move the text spanned by the row range to be after the last line of the row range
 5142            if end_row <= buffer.max_point().row {
 5143                let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
 5144                let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
 5145
 5146                // Don't move lines across excerpt boundaries
 5147                if buffer
 5148                    .excerpt_boundaries_in_range((
 5149                        Bound::Excluded(range_to_move.start),
 5150                        Bound::Included(insertion_point),
 5151                    ))
 5152                    .next()
 5153                    .is_none()
 5154                {
 5155                    let mut text = String::from("\n");
 5156                    text.extend(buffer.text_for_range(range_to_move.clone()));
 5157                    text.pop(); // Drop trailing newline
 5158                    edits.push((
 5159                        buffer.anchor_after(range_to_move.start)
 5160                            ..buffer.anchor_before(range_to_move.end),
 5161                        String::new(),
 5162                    ));
 5163                    let insertion_anchor = buffer.anchor_after(insertion_point);
 5164                    edits.push((insertion_anchor..insertion_anchor, text));
 5165
 5166                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
 5167
 5168                    // Move selections down
 5169                    new_selections.extend(contiguous_row_selections.drain(..).map(
 5170                        |mut selection| {
 5171                            selection.start.row += row_delta;
 5172                            selection.end.row += row_delta;
 5173                            selection
 5174                        },
 5175                    ));
 5176
 5177                    // Move folds down
 5178                    unfold_ranges.push(range_to_move.clone());
 5179                    for fold in display_map.folds_in_range(
 5180                        buffer.anchor_before(range_to_move.start)
 5181                            ..buffer.anchor_after(range_to_move.end),
 5182                    ) {
 5183                        let mut start = fold.range.start.to_point(&buffer);
 5184                        let mut end = fold.range.end.to_point(&buffer);
 5185                        start.row += row_delta;
 5186                        end.row += row_delta;
 5187                        refold_ranges.push(start..end);
 5188                    }
 5189                }
 5190            }
 5191
 5192            // If we didn't move line(s), preserve the existing selections
 5193            new_selections.append(&mut contiguous_row_selections);
 5194        }
 5195
 5196        self.transact(cx, |this, cx| {
 5197            this.unfold_ranges(unfold_ranges, true, true, cx);
 5198            this.buffer.update(cx, |buffer, cx| {
 5199                for (range, text) in edits {
 5200                    buffer.edit([(range, text)], None, cx);
 5201                }
 5202            });
 5203            this.fold_ranges(refold_ranges, true, cx);
 5204            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
 5205        });
 5206    }
 5207
 5208    pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
 5209        let text_layout_details = &self.text_layout_details(cx);
 5210        self.transact(cx, |this, cx| {
 5211            let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5212                let mut edits: Vec<(Range<usize>, String)> = Default::default();
 5213                let line_mode = s.line_mode;
 5214                s.move_with(|display_map, selection| {
 5215                    if !selection.is_empty() || line_mode {
 5216                        return;
 5217                    }
 5218
 5219                    let mut head = selection.head();
 5220                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
 5221                    if head.column() == display_map.line_len(head.row()) {
 5222                        transpose_offset = display_map
 5223                            .buffer_snapshot
 5224                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 5225                    }
 5226
 5227                    if transpose_offset == 0 {
 5228                        return;
 5229                    }
 5230
 5231                    *head.column_mut() += 1;
 5232                    head = display_map.clip_point(head, Bias::Right);
 5233                    let goal = SelectionGoal::HorizontalPosition(
 5234                        display_map
 5235                            .x_for_display_point(head, &text_layout_details)
 5236                            .into(),
 5237                    );
 5238                    selection.collapse_to(head, goal);
 5239
 5240                    let transpose_start = display_map
 5241                        .buffer_snapshot
 5242                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
 5243                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
 5244                        let transpose_end = display_map
 5245                            .buffer_snapshot
 5246                            .clip_offset(transpose_offset + 1, Bias::Right);
 5247                        if let Some(ch) =
 5248                            display_map.buffer_snapshot.chars_at(transpose_start).next()
 5249                        {
 5250                            edits.push((transpose_start..transpose_offset, String::new()));
 5251                            edits.push((transpose_end..transpose_end, ch.to_string()));
 5252                        }
 5253                    }
 5254                });
 5255                edits
 5256            });
 5257            this.buffer
 5258                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 5259            let selections = this.selections.all::<usize>(cx);
 5260            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5261                s.select(selections);
 5262            });
 5263        });
 5264    }
 5265
 5266    pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
 5267        let mut text = String::new();
 5268        let buffer = self.buffer.read(cx).snapshot(cx);
 5269        let mut selections = self.selections.all::<Point>(cx);
 5270        let mut clipboard_selections = Vec::with_capacity(selections.len());
 5271        {
 5272            let max_point = buffer.max_point();
 5273            let mut is_first = true;
 5274            for selection in &mut selections {
 5275                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 5276                if is_entire_line {
 5277                    selection.start = Point::new(selection.start.row, 0);
 5278                    selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
 5279                    selection.goal = SelectionGoal::None;
 5280                }
 5281                if is_first {
 5282                    is_first = false;
 5283                } else {
 5284                    text += "\n";
 5285                }
 5286                let mut len = 0;
 5287                for chunk in buffer.text_for_range(selection.start..selection.end) {
 5288                    text.push_str(chunk);
 5289                    len += chunk.len();
 5290                }
 5291                clipboard_selections.push(ClipboardSelection {
 5292                    len,
 5293                    is_entire_line,
 5294                    first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
 5295                });
 5296            }
 5297        }
 5298
 5299        self.transact(cx, |this, cx| {
 5300            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5301                s.select(selections);
 5302            });
 5303            this.insert("", cx);
 5304            cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
 5305        });
 5306    }
 5307
 5308    pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
 5309        let selections = self.selections.all::<Point>(cx);
 5310        let buffer = self.buffer.read(cx).read(cx);
 5311        let mut text = String::new();
 5312
 5313        let mut clipboard_selections = Vec::with_capacity(selections.len());
 5314        {
 5315            let max_point = buffer.max_point();
 5316            let mut is_first = true;
 5317            for selection in selections.iter() {
 5318                let mut start = selection.start;
 5319                let mut end = selection.end;
 5320                let is_entire_line = selection.is_empty() || self.selections.line_mode;
 5321                if is_entire_line {
 5322                    start = Point::new(start.row, 0);
 5323                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
 5324                }
 5325                if is_first {
 5326                    is_first = false;
 5327                } else {
 5328                    text += "\n";
 5329                }
 5330                let mut len = 0;
 5331                for chunk in buffer.text_for_range(start..end) {
 5332                    text.push_str(chunk);
 5333                    len += chunk.len();
 5334                }
 5335                clipboard_selections.push(ClipboardSelection {
 5336                    len,
 5337                    is_entire_line,
 5338                    first_line_indent: buffer.indent_size_for_line(start.row).len,
 5339                });
 5340            }
 5341        }
 5342
 5343        cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
 5344    }
 5345
 5346    pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
 5347        if self.read_only(cx) {
 5348            return;
 5349        }
 5350
 5351        self.transact(cx, |this, cx| {
 5352            if let Some(item) = cx.read_from_clipboard() {
 5353                let clipboard_text = Cow::Borrowed(item.text());
 5354                if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
 5355                    let old_selections = this.selections.all::<usize>(cx);
 5356                    let all_selections_were_entire_line =
 5357                        clipboard_selections.iter().all(|s| s.is_entire_line);
 5358                    let first_selection_indent_column =
 5359                        clipboard_selections.first().map(|s| s.first_line_indent);
 5360                    if clipboard_selections.len() != old_selections.len() {
 5361                        clipboard_selections.drain(..);
 5362                    }
 5363
 5364                    this.buffer.update(cx, |buffer, cx| {
 5365                        let snapshot = buffer.read(cx);
 5366                        let mut start_offset = 0;
 5367                        let mut edits = Vec::new();
 5368                        let mut original_indent_columns = Vec::new();
 5369                        let line_mode = this.selections.line_mode;
 5370                        for (ix, selection) in old_selections.iter().enumerate() {
 5371                            let to_insert;
 5372                            let entire_line;
 5373                            let original_indent_column;
 5374                            if let Some(clipboard_selection) = clipboard_selections.get(ix) {
 5375                                let end_offset = start_offset + clipboard_selection.len;
 5376                                to_insert = &clipboard_text[start_offset..end_offset];
 5377                                entire_line = clipboard_selection.is_entire_line;
 5378                                start_offset = end_offset + 1;
 5379                                original_indent_column =
 5380                                    Some(clipboard_selection.first_line_indent);
 5381                            } else {
 5382                                to_insert = clipboard_text.as_str();
 5383                                entire_line = all_selections_were_entire_line;
 5384                                original_indent_column = first_selection_indent_column
 5385                            }
 5386
 5387                            // If the corresponding selection was empty when this slice of the
 5388                            // clipboard text was written, then the entire line containing the
 5389                            // selection was copied. If this selection is also currently empty,
 5390                            // then paste the line before the current line of the buffer.
 5391                            let range = if selection.is_empty() && !line_mode && entire_line {
 5392                                let column = selection.start.to_point(&snapshot).column as usize;
 5393                                let line_start = selection.start - column;
 5394                                line_start..line_start
 5395                            } else {
 5396                                selection.range()
 5397                            };
 5398
 5399                            edits.push((range, to_insert));
 5400                            original_indent_columns.extend(original_indent_column);
 5401                        }
 5402                        drop(snapshot);
 5403
 5404                        buffer.edit(
 5405                            edits,
 5406                            Some(AutoindentMode::Block {
 5407                                original_indent_columns,
 5408                            }),
 5409                            cx,
 5410                        );
 5411                    });
 5412
 5413                    let selections = this.selections.all::<usize>(cx);
 5414                    this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 5415                } else {
 5416                    this.insert(&clipboard_text, cx);
 5417                }
 5418            }
 5419        });
 5420    }
 5421
 5422    pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
 5423        if self.read_only(cx) {
 5424            return;
 5425        }
 5426
 5427        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
 5428            if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
 5429                self.change_selections(None, cx, |s| {
 5430                    s.select_anchors(selections.to_vec());
 5431                });
 5432            }
 5433            self.request_autoscroll(Autoscroll::fit(), cx);
 5434            self.unmark_text(cx);
 5435            self.refresh_copilot_suggestions(true, cx);
 5436            cx.emit(EditorEvent::Edited);
 5437        }
 5438    }
 5439
 5440    pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
 5441        if self.read_only(cx) {
 5442            return;
 5443        }
 5444
 5445        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
 5446            if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
 5447            {
 5448                self.change_selections(None, cx, |s| {
 5449                    s.select_anchors(selections.to_vec());
 5450                });
 5451            }
 5452            self.request_autoscroll(Autoscroll::fit(), cx);
 5453            self.unmark_text(cx);
 5454            self.refresh_copilot_suggestions(true, cx);
 5455            cx.emit(EditorEvent::Edited);
 5456        }
 5457    }
 5458
 5459    pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
 5460        self.buffer
 5461            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
 5462    }
 5463
 5464    pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
 5465        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5466            let line_mode = s.line_mode;
 5467            s.move_with(|map, selection| {
 5468                let cursor = if selection.is_empty() && !line_mode {
 5469                    movement::left(map, selection.start)
 5470                } else {
 5471                    selection.start
 5472                };
 5473                selection.collapse_to(cursor, SelectionGoal::None);
 5474            });
 5475        })
 5476    }
 5477
 5478    pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
 5479        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5480            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
 5481        })
 5482    }
 5483
 5484    pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
 5485        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5486            let line_mode = s.line_mode;
 5487            s.move_with(|map, selection| {
 5488                let cursor = if selection.is_empty() && !line_mode {
 5489                    movement::right(map, selection.end)
 5490                } else {
 5491                    selection.end
 5492                };
 5493                selection.collapse_to(cursor, SelectionGoal::None)
 5494            });
 5495        })
 5496    }
 5497
 5498    pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
 5499        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5500            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
 5501        })
 5502    }
 5503
 5504    pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
 5505        if self.take_rename(true, cx).is_some() {
 5506            return;
 5507        }
 5508
 5509        if matches!(self.mode, EditorMode::SingleLine) {
 5510            cx.propagate();
 5511            return;
 5512        }
 5513
 5514        let text_layout_details = &self.text_layout_details(cx);
 5515
 5516        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5517            let line_mode = s.line_mode;
 5518            s.move_with(|map, selection| {
 5519                if !selection.is_empty() && !line_mode {
 5520                    selection.goal = SelectionGoal::None;
 5521                }
 5522                let (cursor, goal) = movement::up(
 5523                    map,
 5524                    selection.start,
 5525                    selection.goal,
 5526                    false,
 5527                    &text_layout_details,
 5528                );
 5529                selection.collapse_to(cursor, goal);
 5530            });
 5531        })
 5532    }
 5533
 5534    pub fn move_up_by_lines(&mut self, action: &MoveUpByLines, cx: &mut ViewContext<Self>) {
 5535        if self.take_rename(true, cx).is_some() {
 5536            return;
 5537        }
 5538
 5539        if matches!(self.mode, EditorMode::SingleLine) {
 5540            cx.propagate();
 5541            return;
 5542        }
 5543
 5544        let text_layout_details = &self.text_layout_details(cx);
 5545
 5546        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5547            let line_mode = s.line_mode;
 5548            s.move_with(|map, selection| {
 5549                if !selection.is_empty() && !line_mode {
 5550                    selection.goal = SelectionGoal::None;
 5551                }
 5552                let (cursor, goal) = movement::up_by_rows(
 5553                    map,
 5554                    selection.start,
 5555                    action.lines,
 5556                    selection.goal,
 5557                    false,
 5558                    &text_layout_details,
 5559                );
 5560                selection.collapse_to(cursor, goal);
 5561            });
 5562        })
 5563    }
 5564
 5565    pub fn move_down_by_lines(&mut self, action: &MoveDownByLines, cx: &mut ViewContext<Self>) {
 5566        if self.take_rename(true, cx).is_some() {
 5567            return;
 5568        }
 5569
 5570        if matches!(self.mode, EditorMode::SingleLine) {
 5571            cx.propagate();
 5572            return;
 5573        }
 5574
 5575        let text_layout_details = &self.text_layout_details(cx);
 5576
 5577        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5578            let line_mode = s.line_mode;
 5579            s.move_with(|map, selection| {
 5580                if !selection.is_empty() && !line_mode {
 5581                    selection.goal = SelectionGoal::None;
 5582                }
 5583                let (cursor, goal) = movement::down_by_rows(
 5584                    map,
 5585                    selection.start,
 5586                    action.lines,
 5587                    selection.goal,
 5588                    false,
 5589                    &text_layout_details,
 5590                );
 5591                selection.collapse_to(cursor, goal);
 5592            });
 5593        })
 5594    }
 5595
 5596    pub fn select_down_by_lines(&mut self, action: &SelectDownByLines, cx: &mut ViewContext<Self>) {
 5597        let text_layout_details = &self.text_layout_details(cx);
 5598        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5599            s.move_heads_with(|map, head, goal| {
 5600                movement::down_by_rows(map, head, action.lines, goal, false, &text_layout_details)
 5601            })
 5602        })
 5603    }
 5604
 5605    pub fn select_up_by_lines(&mut self, action: &SelectUpByLines, cx: &mut ViewContext<Self>) {
 5606        let text_layout_details = &self.text_layout_details(cx);
 5607        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5608            s.move_heads_with(|map, head, goal| {
 5609                movement::up_by_rows(map, head, action.lines, goal, false, &text_layout_details)
 5610            })
 5611        })
 5612    }
 5613
 5614    pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
 5615        if self.take_rename(true, cx).is_some() {
 5616            return;
 5617        }
 5618
 5619        if matches!(self.mode, EditorMode::SingleLine) {
 5620            cx.propagate();
 5621            return;
 5622        }
 5623
 5624        let row_count = if let Some(row_count) = self.visible_line_count() {
 5625            row_count as u32 - 1
 5626        } else {
 5627            return;
 5628        };
 5629
 5630        let autoscroll = if action.center_cursor {
 5631            Autoscroll::center()
 5632        } else {
 5633            Autoscroll::fit()
 5634        };
 5635
 5636        let text_layout_details = &self.text_layout_details(cx);
 5637
 5638        self.change_selections(Some(autoscroll), cx, |s| {
 5639            let line_mode = s.line_mode;
 5640            s.move_with(|map, selection| {
 5641                if !selection.is_empty() && !line_mode {
 5642                    selection.goal = SelectionGoal::None;
 5643                }
 5644                let (cursor, goal) = movement::up_by_rows(
 5645                    map,
 5646                    selection.end,
 5647                    row_count,
 5648                    selection.goal,
 5649                    false,
 5650                    &text_layout_details,
 5651                );
 5652                selection.collapse_to(cursor, goal);
 5653            });
 5654        });
 5655    }
 5656
 5657    pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
 5658        let text_layout_details = &self.text_layout_details(cx);
 5659        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5660            s.move_heads_with(|map, head, goal| {
 5661                movement::up(map, head, goal, false, &text_layout_details)
 5662            })
 5663        })
 5664    }
 5665
 5666    pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
 5667        self.take_rename(true, cx);
 5668
 5669        if self.mode == EditorMode::SingleLine {
 5670            cx.propagate();
 5671            return;
 5672        }
 5673
 5674        let text_layout_details = &self.text_layout_details(cx);
 5675        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5676            let line_mode = s.line_mode;
 5677            s.move_with(|map, selection| {
 5678                if !selection.is_empty() && !line_mode {
 5679                    selection.goal = SelectionGoal::None;
 5680                }
 5681                let (cursor, goal) = movement::down(
 5682                    map,
 5683                    selection.end,
 5684                    selection.goal,
 5685                    false,
 5686                    &text_layout_details,
 5687                );
 5688                selection.collapse_to(cursor, goal);
 5689            });
 5690        });
 5691    }
 5692
 5693    pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
 5694        if self.take_rename(true, cx).is_some() {
 5695            return;
 5696        }
 5697
 5698        if self
 5699            .context_menu
 5700            .write()
 5701            .as_mut()
 5702            .map(|menu| menu.select_last(self.project.as_ref(), cx))
 5703            .unwrap_or(false)
 5704        {
 5705            return;
 5706        }
 5707
 5708        if matches!(self.mode, EditorMode::SingleLine) {
 5709            cx.propagate();
 5710            return;
 5711        }
 5712
 5713        let row_count = if let Some(row_count) = self.visible_line_count() {
 5714            row_count as u32 - 1
 5715        } else {
 5716            return;
 5717        };
 5718
 5719        let autoscroll = if action.center_cursor {
 5720            Autoscroll::center()
 5721        } else {
 5722            Autoscroll::fit()
 5723        };
 5724
 5725        let text_layout_details = &self.text_layout_details(cx);
 5726        self.change_selections(Some(autoscroll), cx, |s| {
 5727            let line_mode = s.line_mode;
 5728            s.move_with(|map, selection| {
 5729                if !selection.is_empty() && !line_mode {
 5730                    selection.goal = SelectionGoal::None;
 5731                }
 5732                let (cursor, goal) = movement::down_by_rows(
 5733                    map,
 5734                    selection.end,
 5735                    row_count,
 5736                    selection.goal,
 5737                    false,
 5738                    &text_layout_details,
 5739                );
 5740                selection.collapse_to(cursor, goal);
 5741            });
 5742        });
 5743    }
 5744
 5745    pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
 5746        let text_layout_details = &self.text_layout_details(cx);
 5747        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5748            s.move_heads_with(|map, head, goal| {
 5749                movement::down(map, head, goal, false, &text_layout_details)
 5750            })
 5751        });
 5752    }
 5753
 5754    pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
 5755        if let Some(context_menu) = self.context_menu.write().as_mut() {
 5756            context_menu.select_first(self.project.as_ref(), cx);
 5757        }
 5758    }
 5759
 5760    pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
 5761        if let Some(context_menu) = self.context_menu.write().as_mut() {
 5762            context_menu.select_prev(self.project.as_ref(), cx);
 5763        }
 5764    }
 5765
 5766    pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
 5767        if let Some(context_menu) = self.context_menu.write().as_mut() {
 5768            context_menu.select_next(self.project.as_ref(), cx);
 5769        }
 5770    }
 5771
 5772    pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
 5773        if let Some(context_menu) = self.context_menu.write().as_mut() {
 5774            context_menu.select_last(self.project.as_ref(), cx);
 5775        }
 5776    }
 5777
 5778    pub fn move_to_previous_word_start(
 5779        &mut self,
 5780        _: &MoveToPreviousWordStart,
 5781        cx: &mut ViewContext<Self>,
 5782    ) {
 5783        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5784            s.move_cursors_with(|map, head, _| {
 5785                (
 5786                    movement::previous_word_start(map, head),
 5787                    SelectionGoal::None,
 5788                )
 5789            });
 5790        })
 5791    }
 5792
 5793    pub fn move_to_previous_subword_start(
 5794        &mut self,
 5795        _: &MoveToPreviousSubwordStart,
 5796        cx: &mut ViewContext<Self>,
 5797    ) {
 5798        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5799            s.move_cursors_with(|map, head, _| {
 5800                (
 5801                    movement::previous_subword_start(map, head),
 5802                    SelectionGoal::None,
 5803                )
 5804            });
 5805        })
 5806    }
 5807
 5808    pub fn select_to_previous_word_start(
 5809        &mut self,
 5810        _: &SelectToPreviousWordStart,
 5811        cx: &mut ViewContext<Self>,
 5812    ) {
 5813        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5814            s.move_heads_with(|map, head, _| {
 5815                (
 5816                    movement::previous_word_start(map, head),
 5817                    SelectionGoal::None,
 5818                )
 5819            });
 5820        })
 5821    }
 5822
 5823    pub fn select_to_previous_subword_start(
 5824        &mut self,
 5825        _: &SelectToPreviousSubwordStart,
 5826        cx: &mut ViewContext<Self>,
 5827    ) {
 5828        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5829            s.move_heads_with(|map, head, _| {
 5830                (
 5831                    movement::previous_subword_start(map, head),
 5832                    SelectionGoal::None,
 5833                )
 5834            });
 5835        })
 5836    }
 5837
 5838    pub fn delete_to_previous_word_start(
 5839        &mut self,
 5840        _: &DeleteToPreviousWordStart,
 5841        cx: &mut ViewContext<Self>,
 5842    ) {
 5843        self.transact(cx, |this, cx| {
 5844            this.select_autoclose_pair(cx);
 5845            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5846                let line_mode = s.line_mode;
 5847                s.move_with(|map, selection| {
 5848                    if selection.is_empty() && !line_mode {
 5849                        let cursor = movement::previous_word_start(map, selection.head());
 5850                        selection.set_head(cursor, SelectionGoal::None);
 5851                    }
 5852                });
 5853            });
 5854            this.insert("", cx);
 5855        });
 5856    }
 5857
 5858    pub fn delete_to_previous_subword_start(
 5859        &mut self,
 5860        _: &DeleteToPreviousSubwordStart,
 5861        cx: &mut ViewContext<Self>,
 5862    ) {
 5863        self.transact(cx, |this, cx| {
 5864            this.select_autoclose_pair(cx);
 5865            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5866                let line_mode = s.line_mode;
 5867                s.move_with(|map, selection| {
 5868                    if selection.is_empty() && !line_mode {
 5869                        let cursor = movement::previous_subword_start(map, selection.head());
 5870                        selection.set_head(cursor, SelectionGoal::None);
 5871                    }
 5872                });
 5873            });
 5874            this.insert("", cx);
 5875        });
 5876    }
 5877
 5878    pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
 5879        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5880            s.move_cursors_with(|map, head, _| {
 5881                (movement::next_word_end(map, head), SelectionGoal::None)
 5882            });
 5883        })
 5884    }
 5885
 5886    pub fn move_to_next_subword_end(
 5887        &mut self,
 5888        _: &MoveToNextSubwordEnd,
 5889        cx: &mut ViewContext<Self>,
 5890    ) {
 5891        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5892            s.move_cursors_with(|map, head, _| {
 5893                (movement::next_subword_end(map, head), SelectionGoal::None)
 5894            });
 5895        })
 5896    }
 5897
 5898    pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
 5899        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5900            s.move_heads_with(|map, head, _| {
 5901                (movement::next_word_end(map, head), SelectionGoal::None)
 5902            });
 5903        })
 5904    }
 5905
 5906    pub fn select_to_next_subword_end(
 5907        &mut self,
 5908        _: &SelectToNextSubwordEnd,
 5909        cx: &mut ViewContext<Self>,
 5910    ) {
 5911        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5912            s.move_heads_with(|map, head, _| {
 5913                (movement::next_subword_end(map, head), SelectionGoal::None)
 5914            });
 5915        })
 5916    }
 5917
 5918    pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
 5919        self.transact(cx, |this, cx| {
 5920            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5921                let line_mode = s.line_mode;
 5922                s.move_with(|map, selection| {
 5923                    if selection.is_empty() && !line_mode {
 5924                        let cursor = movement::next_word_end(map, selection.head());
 5925                        selection.set_head(cursor, SelectionGoal::None);
 5926                    }
 5927                });
 5928            });
 5929            this.insert("", cx);
 5930        });
 5931    }
 5932
 5933    pub fn delete_to_next_subword_end(
 5934        &mut self,
 5935        _: &DeleteToNextSubwordEnd,
 5936        cx: &mut ViewContext<Self>,
 5937    ) {
 5938        self.transact(cx, |this, cx| {
 5939            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5940                s.move_with(|map, selection| {
 5941                    if selection.is_empty() {
 5942                        let cursor = movement::next_subword_end(map, selection.head());
 5943                        selection.set_head(cursor, SelectionGoal::None);
 5944                    }
 5945                });
 5946            });
 5947            this.insert("", cx);
 5948        });
 5949    }
 5950
 5951    pub fn move_to_beginning_of_line(
 5952        &mut self,
 5953        _: &MoveToBeginningOfLine,
 5954        cx: &mut ViewContext<Self>,
 5955    ) {
 5956        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5957            s.move_cursors_with(|map, head, _| {
 5958                (
 5959                    movement::indented_line_beginning(map, head, true),
 5960                    SelectionGoal::None,
 5961                )
 5962            });
 5963        })
 5964    }
 5965
 5966    pub fn select_to_beginning_of_line(
 5967        &mut self,
 5968        action: &SelectToBeginningOfLine,
 5969        cx: &mut ViewContext<Self>,
 5970    ) {
 5971        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5972            s.move_heads_with(|map, head, _| {
 5973                (
 5974                    movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
 5975                    SelectionGoal::None,
 5976                )
 5977            });
 5978        });
 5979    }
 5980
 5981    pub fn delete_to_beginning_of_line(
 5982        &mut self,
 5983        _: &DeleteToBeginningOfLine,
 5984        cx: &mut ViewContext<Self>,
 5985    ) {
 5986        self.transact(cx, |this, cx| {
 5987            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 5988                s.move_with(|_, selection| {
 5989                    selection.reversed = true;
 5990                });
 5991            });
 5992
 5993            this.select_to_beginning_of_line(
 5994                &SelectToBeginningOfLine {
 5995                    stop_at_soft_wraps: false,
 5996                },
 5997                cx,
 5998            );
 5999            this.backspace(&Backspace, cx);
 6000        });
 6001    }
 6002
 6003    pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
 6004        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6005            s.move_cursors_with(|map, head, _| {
 6006                (movement::line_end(map, head, true), SelectionGoal::None)
 6007            });
 6008        })
 6009    }
 6010
 6011    pub fn select_to_end_of_line(
 6012        &mut self,
 6013        action: &SelectToEndOfLine,
 6014        cx: &mut ViewContext<Self>,
 6015    ) {
 6016        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6017            s.move_heads_with(|map, head, _| {
 6018                (
 6019                    movement::line_end(map, head, action.stop_at_soft_wraps),
 6020                    SelectionGoal::None,
 6021                )
 6022            });
 6023        })
 6024    }
 6025
 6026    pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
 6027        self.transact(cx, |this, cx| {
 6028            this.select_to_end_of_line(
 6029                &SelectToEndOfLine {
 6030                    stop_at_soft_wraps: false,
 6031                },
 6032                cx,
 6033            );
 6034            this.delete(&Delete, cx);
 6035        });
 6036    }
 6037
 6038    pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
 6039        self.transact(cx, |this, cx| {
 6040            this.select_to_end_of_line(
 6041                &SelectToEndOfLine {
 6042                    stop_at_soft_wraps: false,
 6043                },
 6044                cx,
 6045            );
 6046            this.cut(&Cut, cx);
 6047        });
 6048    }
 6049
 6050    pub fn move_to_start_of_paragraph(
 6051        &mut self,
 6052        _: &MoveToStartOfParagraph,
 6053        cx: &mut ViewContext<Self>,
 6054    ) {
 6055        if matches!(self.mode, EditorMode::SingleLine) {
 6056            cx.propagate();
 6057            return;
 6058        }
 6059
 6060        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6061            s.move_with(|map, selection| {
 6062                selection.collapse_to(
 6063                    movement::start_of_paragraph(map, selection.head(), 1),
 6064                    SelectionGoal::None,
 6065                )
 6066            });
 6067        })
 6068    }
 6069
 6070    pub fn move_to_end_of_paragraph(
 6071        &mut self,
 6072        _: &MoveToEndOfParagraph,
 6073        cx: &mut ViewContext<Self>,
 6074    ) {
 6075        if matches!(self.mode, EditorMode::SingleLine) {
 6076            cx.propagate();
 6077            return;
 6078        }
 6079
 6080        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6081            s.move_with(|map, selection| {
 6082                selection.collapse_to(
 6083                    movement::end_of_paragraph(map, selection.head(), 1),
 6084                    SelectionGoal::None,
 6085                )
 6086            });
 6087        })
 6088    }
 6089
 6090    pub fn select_to_start_of_paragraph(
 6091        &mut self,
 6092        _: &SelectToStartOfParagraph,
 6093        cx: &mut ViewContext<Self>,
 6094    ) {
 6095        if matches!(self.mode, EditorMode::SingleLine) {
 6096            cx.propagate();
 6097            return;
 6098        }
 6099
 6100        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6101            s.move_heads_with(|map, head, _| {
 6102                (
 6103                    movement::start_of_paragraph(map, head, 1),
 6104                    SelectionGoal::None,
 6105                )
 6106            });
 6107        })
 6108    }
 6109
 6110    pub fn select_to_end_of_paragraph(
 6111        &mut self,
 6112        _: &SelectToEndOfParagraph,
 6113        cx: &mut ViewContext<Self>,
 6114    ) {
 6115        if matches!(self.mode, EditorMode::SingleLine) {
 6116            cx.propagate();
 6117            return;
 6118        }
 6119
 6120        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6121            s.move_heads_with(|map, head, _| {
 6122                (
 6123                    movement::end_of_paragraph(map, head, 1),
 6124                    SelectionGoal::None,
 6125                )
 6126            });
 6127        })
 6128    }
 6129
 6130    pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
 6131        if matches!(self.mode, EditorMode::SingleLine) {
 6132            cx.propagate();
 6133            return;
 6134        }
 6135
 6136        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6137            s.select_ranges(vec![0..0]);
 6138        });
 6139    }
 6140
 6141    pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
 6142        let mut selection = self.selections.last::<Point>(cx);
 6143        selection.set_head(Point::zero(), SelectionGoal::None);
 6144
 6145        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6146            s.select(vec![selection]);
 6147        });
 6148    }
 6149
 6150    pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
 6151        if matches!(self.mode, EditorMode::SingleLine) {
 6152            cx.propagate();
 6153            return;
 6154        }
 6155
 6156        let cursor = self.buffer.read(cx).read(cx).len();
 6157        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6158            s.select_ranges(vec![cursor..cursor])
 6159        });
 6160    }
 6161
 6162    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
 6163        self.nav_history = nav_history;
 6164    }
 6165
 6166    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
 6167        self.nav_history.as_ref()
 6168    }
 6169
 6170    fn push_to_nav_history(
 6171        &mut self,
 6172        cursor_anchor: Anchor,
 6173        new_position: Option<Point>,
 6174        cx: &mut ViewContext<Self>,
 6175    ) {
 6176        if let Some(nav_history) = self.nav_history.as_mut() {
 6177            let buffer = self.buffer.read(cx).read(cx);
 6178            let cursor_position = cursor_anchor.to_point(&buffer);
 6179            let scroll_state = self.scroll_manager.anchor();
 6180            let scroll_top_row = scroll_state.top_row(&buffer);
 6181            drop(buffer);
 6182
 6183            if let Some(new_position) = new_position {
 6184                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
 6185                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
 6186                    return;
 6187                }
 6188            }
 6189
 6190            nav_history.push(
 6191                Some(NavigationData {
 6192                    cursor_anchor,
 6193                    cursor_position,
 6194                    scroll_anchor: scroll_state,
 6195                    scroll_top_row,
 6196                }),
 6197                cx,
 6198            );
 6199        }
 6200    }
 6201
 6202    pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
 6203        let buffer = self.buffer.read(cx).snapshot(cx);
 6204        let mut selection = self.selections.first::<usize>(cx);
 6205        selection.set_head(buffer.len(), SelectionGoal::None);
 6206        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6207            s.select(vec![selection]);
 6208        });
 6209    }
 6210
 6211    pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
 6212        let end = self.buffer.read(cx).read(cx).len();
 6213        self.change_selections(None, cx, |s| {
 6214            s.select_ranges(vec![0..end]);
 6215        });
 6216    }
 6217
 6218    pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
 6219        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6220        let mut selections = self.selections.all::<Point>(cx);
 6221        let max_point = display_map.buffer_snapshot.max_point();
 6222        for selection in &mut selections {
 6223            let rows = selection.spanned_rows(true, &display_map);
 6224            selection.start = Point::new(rows.start, 0);
 6225            selection.end = cmp::min(max_point, Point::new(rows.end, 0));
 6226            selection.reversed = false;
 6227        }
 6228        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6229            s.select(selections);
 6230        });
 6231    }
 6232
 6233    pub fn split_selection_into_lines(
 6234        &mut self,
 6235        _: &SplitSelectionIntoLines,
 6236        cx: &mut ViewContext<Self>,
 6237    ) {
 6238        let mut to_unfold = Vec::new();
 6239        let mut new_selection_ranges = Vec::new();
 6240        {
 6241            let selections = self.selections.all::<Point>(cx);
 6242            let buffer = self.buffer.read(cx).read(cx);
 6243            for selection in selections {
 6244                for row in selection.start.row..selection.end.row {
 6245                    let cursor = Point::new(row, buffer.line_len(row));
 6246                    new_selection_ranges.push(cursor..cursor);
 6247                }
 6248                new_selection_ranges.push(selection.end..selection.end);
 6249                to_unfold.push(selection.start..selection.end);
 6250            }
 6251        }
 6252        self.unfold_ranges(to_unfold, true, true, cx);
 6253        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6254            s.select_ranges(new_selection_ranges);
 6255        });
 6256    }
 6257
 6258    pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
 6259        self.add_selection(true, cx);
 6260    }
 6261
 6262    pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
 6263        self.add_selection(false, cx);
 6264    }
 6265
 6266    fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
 6267        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6268        let mut selections = self.selections.all::<Point>(cx);
 6269        let text_layout_details = self.text_layout_details(cx);
 6270        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
 6271            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
 6272            let range = oldest_selection.display_range(&display_map).sorted();
 6273
 6274            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
 6275            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
 6276            let positions = start_x.min(end_x)..start_x.max(end_x);
 6277
 6278            selections.clear();
 6279            let mut stack = Vec::new();
 6280            for row in range.start.row()..=range.end.row() {
 6281                if let Some(selection) = self.selections.build_columnar_selection(
 6282                    &display_map,
 6283                    row,
 6284                    &positions,
 6285                    oldest_selection.reversed,
 6286                    &text_layout_details,
 6287                ) {
 6288                    stack.push(selection.id);
 6289                    selections.push(selection);
 6290                }
 6291            }
 6292
 6293            if above {
 6294                stack.reverse();
 6295            }
 6296
 6297            AddSelectionsState { above, stack }
 6298        });
 6299
 6300        let last_added_selection = *state.stack.last().unwrap();
 6301        let mut new_selections = Vec::new();
 6302        if above == state.above {
 6303            let end_row = if above {
 6304                0
 6305            } else {
 6306                display_map.max_point().row()
 6307            };
 6308
 6309            'outer: for selection in selections {
 6310                if selection.id == last_added_selection {
 6311                    let range = selection.display_range(&display_map).sorted();
 6312                    debug_assert_eq!(range.start.row(), range.end.row());
 6313                    let mut row = range.start.row();
 6314                    let positions =
 6315                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
 6316                            px(start)..px(end)
 6317                        } else {
 6318                            let start_x =
 6319                                display_map.x_for_display_point(range.start, &text_layout_details);
 6320                            let end_x =
 6321                                display_map.x_for_display_point(range.end, &text_layout_details);
 6322                            start_x.min(end_x)..start_x.max(end_x)
 6323                        };
 6324
 6325                    while row != end_row {
 6326                        if above {
 6327                            row -= 1;
 6328                        } else {
 6329                            row += 1;
 6330                        }
 6331
 6332                        if let Some(new_selection) = self.selections.build_columnar_selection(
 6333                            &display_map,
 6334                            row,
 6335                            &positions,
 6336                            selection.reversed,
 6337                            &text_layout_details,
 6338                        ) {
 6339                            state.stack.push(new_selection.id);
 6340                            if above {
 6341                                new_selections.push(new_selection);
 6342                                new_selections.push(selection);
 6343                            } else {
 6344                                new_selections.push(selection);
 6345                                new_selections.push(new_selection);
 6346                            }
 6347
 6348                            continue 'outer;
 6349                        }
 6350                    }
 6351                }
 6352
 6353                new_selections.push(selection);
 6354            }
 6355        } else {
 6356            new_selections = selections;
 6357            new_selections.retain(|s| s.id != last_added_selection);
 6358            state.stack.pop();
 6359        }
 6360
 6361        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 6362            s.select(new_selections);
 6363        });
 6364        if state.stack.len() > 1 {
 6365            self.add_selections_state = Some(state);
 6366        }
 6367    }
 6368
 6369    pub fn select_next_match_internal(
 6370        &mut self,
 6371        display_map: &DisplaySnapshot,
 6372        replace_newest: bool,
 6373        autoscroll: Option<Autoscroll>,
 6374        cx: &mut ViewContext<Self>,
 6375    ) -> Result<()> {
 6376        fn select_next_match_ranges(
 6377            this: &mut Editor,
 6378            range: Range<usize>,
 6379            replace_newest: bool,
 6380            auto_scroll: Option<Autoscroll>,
 6381            cx: &mut ViewContext<Editor>,
 6382        ) {
 6383            this.unfold_ranges([range.clone()], false, true, cx);
 6384            this.change_selections(auto_scroll, cx, |s| {
 6385                if replace_newest {
 6386                    s.delete(s.newest_anchor().id);
 6387                }
 6388                s.insert_range(range.clone());
 6389            });
 6390        }
 6391
 6392        let buffer = &display_map.buffer_snapshot;
 6393        let mut selections = self.selections.all::<usize>(cx);
 6394        if let Some(mut select_next_state) = self.select_next_state.take() {
 6395            let query = &select_next_state.query;
 6396            if !select_next_state.done {
 6397                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
 6398                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
 6399                let mut next_selected_range = None;
 6400
 6401                let bytes_after_last_selection =
 6402                    buffer.bytes_in_range(last_selection.end..buffer.len());
 6403                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
 6404                let query_matches = query
 6405                    .stream_find_iter(bytes_after_last_selection)
 6406                    .map(|result| (last_selection.end, result))
 6407                    .chain(
 6408                        query
 6409                            .stream_find_iter(bytes_before_first_selection)
 6410                            .map(|result| (0, result)),
 6411                    );
 6412
 6413                for (start_offset, query_match) in query_matches {
 6414                    let query_match = query_match.unwrap(); // can only fail due to I/O
 6415                    let offset_range =
 6416                        start_offset + query_match.start()..start_offset + query_match.end();
 6417                    let display_range = offset_range.start.to_display_point(&display_map)
 6418                        ..offset_range.end.to_display_point(&display_map);
 6419
 6420                    if !select_next_state.wordwise
 6421                        || (!movement::is_inside_word(&display_map, display_range.start)
 6422                            && !movement::is_inside_word(&display_map, display_range.end))
 6423                    {
 6424                        // TODO: This is n^2, because we might check all the selections
 6425                        if selections
 6426                            .iter()
 6427                            .find(|selection| selection.range().overlaps(&offset_range))
 6428                            .is_none()
 6429                        {
 6430                            next_selected_range = Some(offset_range);
 6431                            break;
 6432                        }
 6433                    }
 6434                }
 6435
 6436                if let Some(next_selected_range) = next_selected_range {
 6437                    select_next_match_ranges(
 6438                        self,
 6439                        next_selected_range,
 6440                        replace_newest,
 6441                        autoscroll,
 6442                        cx,
 6443                    );
 6444                } else {
 6445                    select_next_state.done = true;
 6446                }
 6447            }
 6448
 6449            self.select_next_state = Some(select_next_state);
 6450        } else {
 6451            let mut only_carets = true;
 6452            let mut same_text_selected = true;
 6453            let mut selected_text = None;
 6454
 6455            let mut selections_iter = selections.iter().peekable();
 6456            while let Some(selection) = selections_iter.next() {
 6457                if selection.start != selection.end {
 6458                    only_carets = false;
 6459                }
 6460
 6461                if same_text_selected {
 6462                    if selected_text.is_none() {
 6463                        selected_text =
 6464                            Some(buffer.text_for_range(selection.range()).collect::<String>());
 6465                    }
 6466
 6467                    if let Some(next_selection) = selections_iter.peek() {
 6468                        if next_selection.range().len() == selection.range().len() {
 6469                            let next_selected_text = buffer
 6470                                .text_for_range(next_selection.range())
 6471                                .collect::<String>();
 6472                            if Some(next_selected_text) != selected_text {
 6473                                same_text_selected = false;
 6474                                selected_text = None;
 6475                            }
 6476                        } else {
 6477                            same_text_selected = false;
 6478                            selected_text = None;
 6479                        }
 6480                    }
 6481                }
 6482            }
 6483
 6484            if only_carets {
 6485                for selection in &mut selections {
 6486                    let word_range = movement::surrounding_word(
 6487                        &display_map,
 6488                        selection.start.to_display_point(&display_map),
 6489                    );
 6490                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
 6491                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
 6492                    selection.goal = SelectionGoal::None;
 6493                    selection.reversed = false;
 6494                    select_next_match_ranges(
 6495                        self,
 6496                        selection.start..selection.end,
 6497                        replace_newest,
 6498                        autoscroll,
 6499                        cx,
 6500                    );
 6501                }
 6502
 6503                if selections.len() == 1 {
 6504                    let selection = selections
 6505                        .last()
 6506                        .expect("ensured that there's only one selection");
 6507                    let query = buffer
 6508                        .text_for_range(selection.start..selection.end)
 6509                        .collect::<String>();
 6510                    let is_empty = query.is_empty();
 6511                    let select_state = SelectNextState {
 6512                        query: AhoCorasick::new(&[query])?,
 6513                        wordwise: true,
 6514                        done: is_empty,
 6515                    };
 6516                    self.select_next_state = Some(select_state);
 6517                } else {
 6518                    self.select_next_state = None;
 6519                }
 6520            } else if let Some(selected_text) = selected_text {
 6521                self.select_next_state = Some(SelectNextState {
 6522                    query: AhoCorasick::new(&[selected_text])?,
 6523                    wordwise: false,
 6524                    done: false,
 6525                });
 6526                self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?;
 6527            }
 6528        }
 6529        Ok(())
 6530    }
 6531
 6532    pub fn select_all_matches(
 6533        &mut self,
 6534        _action: &SelectAllMatches,
 6535        cx: &mut ViewContext<Self>,
 6536    ) -> Result<()> {
 6537        self.push_to_selection_history();
 6538        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6539
 6540        self.select_next_match_internal(&display_map, false, None, cx)?;
 6541        let Some(select_next_state) = self.select_next_state.as_mut() else {
 6542            return Ok(());
 6543        };
 6544        if select_next_state.done {
 6545            return Ok(());
 6546        }
 6547
 6548        let mut new_selections = self.selections.all::<usize>(cx);
 6549
 6550        let buffer = &display_map.buffer_snapshot;
 6551        let query_matches = select_next_state
 6552            .query
 6553            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
 6554
 6555        for query_match in query_matches {
 6556            let query_match = query_match.unwrap(); // can only fail due to I/O
 6557            let offset_range = query_match.start()..query_match.end();
 6558            let display_range = offset_range.start.to_display_point(&display_map)
 6559                ..offset_range.end.to_display_point(&display_map);
 6560
 6561            if !select_next_state.wordwise
 6562                || (!movement::is_inside_word(&display_map, display_range.start)
 6563                    && !movement::is_inside_word(&display_map, display_range.end))
 6564            {
 6565                self.selections.change_with(cx, |selections| {
 6566                    new_selections.push(Selection {
 6567                        id: selections.new_selection_id(),
 6568                        start: offset_range.start,
 6569                        end: offset_range.end,
 6570                        reversed: false,
 6571                        goal: SelectionGoal::None,
 6572                    });
 6573                });
 6574            }
 6575        }
 6576
 6577        new_selections.sort_by_key(|selection| selection.start);
 6578        let mut ix = 0;
 6579        while ix + 1 < new_selections.len() {
 6580            let current_selection = &new_selections[ix];
 6581            let next_selection = &new_selections[ix + 1];
 6582            if current_selection.range().overlaps(&next_selection.range()) {
 6583                if current_selection.id < next_selection.id {
 6584                    new_selections.remove(ix + 1);
 6585                } else {
 6586                    new_selections.remove(ix);
 6587                }
 6588            } else {
 6589                ix += 1;
 6590            }
 6591        }
 6592
 6593        select_next_state.done = true;
 6594        self.unfold_ranges(
 6595            new_selections.iter().map(|selection| selection.range()),
 6596            false,
 6597            false,
 6598            cx,
 6599        );
 6600        self.change_selections(Some(Autoscroll::fit()), cx, |selections| {
 6601            selections.select(new_selections)
 6602        });
 6603
 6604        Ok(())
 6605    }
 6606
 6607    pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) -> Result<()> {
 6608        self.push_to_selection_history();
 6609        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6610        self.select_next_match_internal(
 6611            &display_map,
 6612            action.replace_newest,
 6613            Some(Autoscroll::newest()),
 6614            cx,
 6615        )?;
 6616        Ok(())
 6617    }
 6618
 6619    pub fn select_previous(
 6620        &mut self,
 6621        action: &SelectPrevious,
 6622        cx: &mut ViewContext<Self>,
 6623    ) -> Result<()> {
 6624        self.push_to_selection_history();
 6625        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 6626        let buffer = &display_map.buffer_snapshot;
 6627        let mut selections = self.selections.all::<usize>(cx);
 6628        if let Some(mut select_prev_state) = self.select_prev_state.take() {
 6629            let query = &select_prev_state.query;
 6630            if !select_prev_state.done {
 6631                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
 6632                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
 6633                let mut next_selected_range = None;
 6634                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
 6635                let bytes_before_last_selection =
 6636                    buffer.reversed_bytes_in_range(0..last_selection.start);
 6637                let bytes_after_first_selection =
 6638                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
 6639                let query_matches = query
 6640                    .stream_find_iter(bytes_before_last_selection)
 6641                    .map(|result| (last_selection.start, result))
 6642                    .chain(
 6643                        query
 6644                            .stream_find_iter(bytes_after_first_selection)
 6645                            .map(|result| (buffer.len(), result)),
 6646                    );
 6647                for (end_offset, query_match) in query_matches {
 6648                    let query_match = query_match.unwrap(); // can only fail due to I/O
 6649                    let offset_range =
 6650                        end_offset - query_match.end()..end_offset - query_match.start();
 6651                    let display_range = offset_range.start.to_display_point(&display_map)
 6652                        ..offset_range.end.to_display_point(&display_map);
 6653
 6654                    if !select_prev_state.wordwise
 6655                        || (!movement::is_inside_word(&display_map, display_range.start)
 6656                            && !movement::is_inside_word(&display_map, display_range.end))
 6657                    {
 6658                        next_selected_range = Some(offset_range);
 6659                        break;
 6660                    }
 6661                }
 6662
 6663                if let Some(next_selected_range) = next_selected_range {
 6664                    self.unfold_ranges([next_selected_range.clone()], false, true, cx);
 6665                    self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 6666                        if action.replace_newest {
 6667                            s.delete(s.newest_anchor().id);
 6668                        }
 6669                        s.insert_range(next_selected_range);
 6670                    });
 6671                } else {
 6672                    select_prev_state.done = true;
 6673                }
 6674            }
 6675
 6676            self.select_prev_state = Some(select_prev_state);
 6677        } else {
 6678            let mut only_carets = true;
 6679            let mut same_text_selected = true;
 6680            let mut selected_text = None;
 6681
 6682            let mut selections_iter = selections.iter().peekable();
 6683            while let Some(selection) = selections_iter.next() {
 6684                if selection.start != selection.end {
 6685                    only_carets = false;
 6686                }
 6687
 6688                if same_text_selected {
 6689                    if selected_text.is_none() {
 6690                        selected_text =
 6691                            Some(buffer.text_for_range(selection.range()).collect::<String>());
 6692                    }
 6693
 6694                    if let Some(next_selection) = selections_iter.peek() {
 6695                        if next_selection.range().len() == selection.range().len() {
 6696                            let next_selected_text = buffer
 6697                                .text_for_range(next_selection.range())
 6698                                .collect::<String>();
 6699                            if Some(next_selected_text) != selected_text {
 6700                                same_text_selected = false;
 6701                                selected_text = None;
 6702                            }
 6703                        } else {
 6704                            same_text_selected = false;
 6705                            selected_text = None;
 6706                        }
 6707                    }
 6708                }
 6709            }
 6710
 6711            if only_carets {
 6712                for selection in &mut selections {
 6713                    let word_range = movement::surrounding_word(
 6714                        &display_map,
 6715                        selection.start.to_display_point(&display_map),
 6716                    );
 6717                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
 6718                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
 6719                    selection.goal = SelectionGoal::None;
 6720                    selection.reversed = false;
 6721                }
 6722                if selections.len() == 1 {
 6723                    let selection = selections
 6724                        .last()
 6725                        .expect("ensured that there's only one selection");
 6726                    let query = buffer
 6727                        .text_for_range(selection.start..selection.end)
 6728                        .collect::<String>();
 6729                    let is_empty = query.is_empty();
 6730                    let select_state = SelectNextState {
 6731                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
 6732                        wordwise: true,
 6733                        done: is_empty,
 6734                    };
 6735                    self.select_prev_state = Some(select_state);
 6736                } else {
 6737                    self.select_prev_state = None;
 6738                }
 6739
 6740                self.unfold_ranges(
 6741                    selections.iter().map(|s| s.range()).collect::<Vec<_>>(),
 6742                    false,
 6743                    true,
 6744                    cx,
 6745                );
 6746                self.change_selections(Some(Autoscroll::newest()), cx, |s| {
 6747                    s.select(selections);
 6748                });
 6749            } else if let Some(selected_text) = selected_text {
 6750                self.select_prev_state = Some(SelectNextState {
 6751                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
 6752                    wordwise: false,
 6753                    done: false,
 6754                });
 6755                self.select_previous(action, cx)?;
 6756            }
 6757        }
 6758        Ok(())
 6759    }
 6760
 6761    pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
 6762        let text_layout_details = &self.text_layout_details(cx);
 6763        self.transact(cx, |this, cx| {
 6764            let mut selections = this.selections.all::<Point>(cx);
 6765            let mut edits = Vec::new();
 6766            let mut selection_edit_ranges = Vec::new();
 6767            let mut last_toggled_row = None;
 6768            let snapshot = this.buffer.read(cx).read(cx);
 6769            let empty_str: Arc<str> = "".into();
 6770            let mut suffixes_inserted = Vec::new();
 6771
 6772            fn comment_prefix_range(
 6773                snapshot: &MultiBufferSnapshot,
 6774                row: u32,
 6775                comment_prefix: &str,
 6776                comment_prefix_whitespace: &str,
 6777            ) -> Range<Point> {
 6778                let start = Point::new(row, snapshot.indent_size_for_line(row).len);
 6779
 6780                let mut line_bytes = snapshot
 6781                    .bytes_in_range(start..snapshot.max_point())
 6782                    .flatten()
 6783                    .copied();
 6784
 6785                // If this line currently begins with the line comment prefix, then record
 6786                // the range containing the prefix.
 6787                if line_bytes
 6788                    .by_ref()
 6789                    .take(comment_prefix.len())
 6790                    .eq(comment_prefix.bytes())
 6791                {
 6792                    // Include any whitespace that matches the comment prefix.
 6793                    let matching_whitespace_len = line_bytes
 6794                        .zip(comment_prefix_whitespace.bytes())
 6795                        .take_while(|(a, b)| a == b)
 6796                        .count() as u32;
 6797                    let end = Point::new(
 6798                        start.row,
 6799                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
 6800                    );
 6801                    start..end
 6802                } else {
 6803                    start..start
 6804                }
 6805            }
 6806
 6807            fn comment_suffix_range(
 6808                snapshot: &MultiBufferSnapshot,
 6809                row: u32,
 6810                comment_suffix: &str,
 6811                comment_suffix_has_leading_space: bool,
 6812            ) -> Range<Point> {
 6813                let end = Point::new(row, snapshot.line_len(row));
 6814                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
 6815
 6816                let mut line_end_bytes = snapshot
 6817                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
 6818                    .flatten()
 6819                    .copied();
 6820
 6821                let leading_space_len = if suffix_start_column > 0
 6822                    && line_end_bytes.next() == Some(b' ')
 6823                    && comment_suffix_has_leading_space
 6824                {
 6825                    1
 6826                } else {
 6827                    0
 6828                };
 6829
 6830                // If this line currently begins with the line comment prefix, then record
 6831                // the range containing the prefix.
 6832                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
 6833                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
 6834                    start..end
 6835                } else {
 6836                    end..end
 6837                }
 6838            }
 6839
 6840            // TODO: Handle selections that cross excerpts
 6841            for selection in &mut selections {
 6842                let start_column = snapshot.indent_size_for_line(selection.start.row).len;
 6843                let language = if let Some(language) =
 6844                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
 6845                {
 6846                    language
 6847                } else {
 6848                    continue;
 6849                };
 6850
 6851                selection_edit_ranges.clear();
 6852
 6853                // If multiple selections contain a given row, avoid processing that
 6854                // row more than once.
 6855                let mut start_row = selection.start.row;
 6856                if last_toggled_row == Some(start_row) {
 6857                    start_row += 1;
 6858                }
 6859                let end_row =
 6860                    if selection.end.row > selection.start.row && selection.end.column == 0 {
 6861                        selection.end.row - 1
 6862                    } else {
 6863                        selection.end.row
 6864                    };
 6865                last_toggled_row = Some(end_row);
 6866
 6867                if start_row > end_row {
 6868                    continue;
 6869                }
 6870
 6871                // If the language has line comments, toggle those.
 6872                if let Some(full_comment_prefix) = language
 6873                    .line_comment_prefixes()
 6874                    .and_then(|prefixes| prefixes.first())
 6875                {
 6876                    // Split the comment prefix's trailing whitespace into a separate string,
 6877                    // as that portion won't be used for detecting if a line is a comment.
 6878                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
 6879                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
 6880                    let mut all_selection_lines_are_comments = true;
 6881
 6882                    for row in start_row..=end_row {
 6883                        if start_row < end_row && snapshot.is_line_blank(row) {
 6884                            continue;
 6885                        }
 6886
 6887                        let prefix_range = comment_prefix_range(
 6888                            snapshot.deref(),
 6889                            row,
 6890                            comment_prefix,
 6891                            comment_prefix_whitespace,
 6892                        );
 6893                        if prefix_range.is_empty() {
 6894                            all_selection_lines_are_comments = false;
 6895                        }
 6896                        selection_edit_ranges.push(prefix_range);
 6897                    }
 6898
 6899                    if all_selection_lines_are_comments {
 6900                        edits.extend(
 6901                            selection_edit_ranges
 6902                                .iter()
 6903                                .cloned()
 6904                                .map(|range| (range, empty_str.clone())),
 6905                        );
 6906                    } else {
 6907                        let min_column = selection_edit_ranges
 6908                            .iter()
 6909                            .map(|r| r.start.column)
 6910                            .min()
 6911                            .unwrap_or(0);
 6912                        edits.extend(selection_edit_ranges.iter().map(|range| {
 6913                            let position = Point::new(range.start.row, min_column);
 6914                            (position..position, full_comment_prefix.clone())
 6915                        }));
 6916                    }
 6917                } else if let Some((full_comment_prefix, comment_suffix)) =
 6918                    language.block_comment_delimiters()
 6919                {
 6920                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
 6921                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
 6922                    let prefix_range = comment_prefix_range(
 6923                        snapshot.deref(),
 6924                        start_row,
 6925                        comment_prefix,
 6926                        comment_prefix_whitespace,
 6927                    );
 6928                    let suffix_range = comment_suffix_range(
 6929                        snapshot.deref(),
 6930                        end_row,
 6931                        comment_suffix.trim_start_matches(' '),
 6932                        comment_suffix.starts_with(' '),
 6933                    );
 6934
 6935                    if prefix_range.is_empty() || suffix_range.is_empty() {
 6936                        edits.push((
 6937                            prefix_range.start..prefix_range.start,
 6938                            full_comment_prefix.clone(),
 6939                        ));
 6940                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
 6941                        suffixes_inserted.push((end_row, comment_suffix.len()));
 6942                    } else {
 6943                        edits.push((prefix_range, empty_str.clone()));
 6944                        edits.push((suffix_range, empty_str.clone()));
 6945                    }
 6946                } else {
 6947                    continue;
 6948                }
 6949            }
 6950
 6951            drop(snapshot);
 6952            this.buffer.update(cx, |buffer, cx| {
 6953                buffer.edit(edits, None, cx);
 6954            });
 6955
 6956            // Adjust selections so that they end before any comment suffixes that
 6957            // were inserted.
 6958            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
 6959            let mut selections = this.selections.all::<Point>(cx);
 6960            let snapshot = this.buffer.read(cx).read(cx);
 6961            for selection in &mut selections {
 6962                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
 6963                    match row.cmp(&selection.end.row) {
 6964                        Ordering::Less => {
 6965                            suffixes_inserted.next();
 6966                            continue;
 6967                        }
 6968                        Ordering::Greater => break,
 6969                        Ordering::Equal => {
 6970                            if selection.end.column == snapshot.line_len(row) {
 6971                                if selection.is_empty() {
 6972                                    selection.start.column -= suffix_len as u32;
 6973                                }
 6974                                selection.end.column -= suffix_len as u32;
 6975                            }
 6976                            break;
 6977                        }
 6978                    }
 6979                }
 6980            }
 6981
 6982            drop(snapshot);
 6983            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
 6984
 6985            let selections = this.selections.all::<Point>(cx);
 6986            let selections_on_single_row = selections.windows(2).all(|selections| {
 6987                selections[0].start.row == selections[1].start.row
 6988                    && selections[0].end.row == selections[1].end.row
 6989                    && selections[0].start.row == selections[0].end.row
 6990            });
 6991            let selections_selecting = selections
 6992                .iter()
 6993                .any(|selection| selection.start != selection.end);
 6994            let advance_downwards = action.advance_downwards
 6995                && selections_on_single_row
 6996                && !selections_selecting
 6997                && this.mode != EditorMode::SingleLine;
 6998
 6999            if advance_downwards {
 7000                let snapshot = this.buffer.read(cx).snapshot(cx);
 7001
 7002                this.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7003                    s.move_cursors_with(|display_snapshot, display_point, _| {
 7004                        let mut point = display_point.to_point(display_snapshot);
 7005                        point.row += 1;
 7006                        point = snapshot.clip_point(point, Bias::Left);
 7007                        let display_point = point.to_display_point(display_snapshot);
 7008                        let goal = SelectionGoal::HorizontalPosition(
 7009                            display_snapshot
 7010                                .x_for_display_point(display_point, &text_layout_details)
 7011                                .into(),
 7012                        );
 7013                        (display_point, goal)
 7014                    })
 7015                });
 7016            }
 7017        });
 7018    }
 7019
 7020    pub fn select_larger_syntax_node(
 7021        &mut self,
 7022        _: &SelectLargerSyntaxNode,
 7023        cx: &mut ViewContext<Self>,
 7024    ) {
 7025        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7026        let buffer = self.buffer.read(cx).snapshot(cx);
 7027        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
 7028
 7029        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
 7030        let mut selected_larger_node = false;
 7031        let new_selections = old_selections
 7032            .iter()
 7033            .map(|selection| {
 7034                let old_range = selection.start..selection.end;
 7035                let mut new_range = old_range.clone();
 7036                while let Some(containing_range) =
 7037                    buffer.range_for_syntax_ancestor(new_range.clone())
 7038                {
 7039                    new_range = containing_range;
 7040                    if !display_map.intersects_fold(new_range.start)
 7041                        && !display_map.intersects_fold(new_range.end)
 7042                    {
 7043                        break;
 7044                    }
 7045                }
 7046
 7047                selected_larger_node |= new_range != old_range;
 7048                Selection {
 7049                    id: selection.id,
 7050                    start: new_range.start,
 7051                    end: new_range.end,
 7052                    goal: SelectionGoal::None,
 7053                    reversed: selection.reversed,
 7054                }
 7055            })
 7056            .collect::<Vec<_>>();
 7057
 7058        if selected_larger_node {
 7059            stack.push(old_selections);
 7060            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7061                s.select(new_selections);
 7062            });
 7063        }
 7064        self.select_larger_syntax_node_stack = stack;
 7065    }
 7066
 7067    pub fn select_smaller_syntax_node(
 7068        &mut self,
 7069        _: &SelectSmallerSyntaxNode,
 7070        cx: &mut ViewContext<Self>,
 7071    ) {
 7072        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
 7073        if let Some(selections) = stack.pop() {
 7074            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7075                s.select(selections.to_vec());
 7076            });
 7077        }
 7078        self.select_larger_syntax_node_stack = stack;
 7079    }
 7080
 7081    pub fn move_to_enclosing_bracket(
 7082        &mut self,
 7083        _: &MoveToEnclosingBracket,
 7084        cx: &mut ViewContext<Self>,
 7085    ) {
 7086        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7087            s.move_offsets_with(|snapshot, selection| {
 7088                let Some(enclosing_bracket_ranges) =
 7089                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
 7090                else {
 7091                    return;
 7092                };
 7093
 7094                let mut best_length = usize::MAX;
 7095                let mut best_inside = false;
 7096                let mut best_in_bracket_range = false;
 7097                let mut best_destination = None;
 7098                for (open, close) in enclosing_bracket_ranges {
 7099                    let close = close.to_inclusive();
 7100                    let length = close.end() - open.start;
 7101                    let inside = selection.start >= open.end && selection.end <= *close.start();
 7102                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
 7103                        || close.contains(&selection.head());
 7104
 7105                    // If best is next to a bracket and current isn't, skip
 7106                    if !in_bracket_range && best_in_bracket_range {
 7107                        continue;
 7108                    }
 7109
 7110                    // Prefer smaller lengths unless best is inside and current isn't
 7111                    if length > best_length && (best_inside || !inside) {
 7112                        continue;
 7113                    }
 7114
 7115                    best_length = length;
 7116                    best_inside = inside;
 7117                    best_in_bracket_range = in_bracket_range;
 7118                    best_destination = Some(
 7119                        if close.contains(&selection.start) && close.contains(&selection.end) {
 7120                            if inside {
 7121                                open.end
 7122                            } else {
 7123                                open.start
 7124                            }
 7125                        } else {
 7126                            if inside {
 7127                                *close.start()
 7128                            } else {
 7129                                *close.end()
 7130                            }
 7131                        },
 7132                    );
 7133                }
 7134
 7135                if let Some(destination) = best_destination {
 7136                    selection.collapse_to(destination, SelectionGoal::None);
 7137                }
 7138            })
 7139        });
 7140    }
 7141
 7142    pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
 7143        self.end_selection(cx);
 7144        self.selection_history.mode = SelectionHistoryMode::Undoing;
 7145        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
 7146            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
 7147            self.select_next_state = entry.select_next_state;
 7148            self.select_prev_state = entry.select_prev_state;
 7149            self.add_selections_state = entry.add_selections_state;
 7150            self.request_autoscroll(Autoscroll::newest(), cx);
 7151        }
 7152        self.selection_history.mode = SelectionHistoryMode::Normal;
 7153    }
 7154
 7155    pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
 7156        self.end_selection(cx);
 7157        self.selection_history.mode = SelectionHistoryMode::Redoing;
 7158        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
 7159            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
 7160            self.select_next_state = entry.select_next_state;
 7161            self.select_prev_state = entry.select_prev_state;
 7162            self.add_selections_state = entry.add_selections_state;
 7163            self.request_autoscroll(Autoscroll::newest(), cx);
 7164        }
 7165        self.selection_history.mode = SelectionHistoryMode::Normal;
 7166    }
 7167
 7168    fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
 7169        self.go_to_diagnostic_impl(Direction::Next, cx)
 7170    }
 7171
 7172    fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
 7173        self.go_to_diagnostic_impl(Direction::Prev, cx)
 7174    }
 7175
 7176    pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
 7177        let buffer = self.buffer.read(cx).snapshot(cx);
 7178        let selection = self.selections.newest::<usize>(cx);
 7179
 7180        // If there is an active Diagnostic Popover jump to its diagnostic instead.
 7181        if direction == Direction::Next {
 7182            if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
 7183                let (group_id, jump_to) = popover.activation_info();
 7184                if self.activate_diagnostics(group_id, cx) {
 7185                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7186                        let mut new_selection = s.newest_anchor().clone();
 7187                        new_selection.collapse_to(jump_to, SelectionGoal::None);
 7188                        s.select_anchors(vec![new_selection.clone()]);
 7189                    });
 7190                }
 7191                return;
 7192            }
 7193        }
 7194
 7195        let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
 7196            active_diagnostics
 7197                .primary_range
 7198                .to_offset(&buffer)
 7199                .to_inclusive()
 7200        });
 7201        let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
 7202            if active_primary_range.contains(&selection.head()) {
 7203                *active_primary_range.end()
 7204            } else {
 7205                selection.head()
 7206            }
 7207        } else {
 7208            selection.head()
 7209        };
 7210
 7211        loop {
 7212            let mut diagnostics = if direction == Direction::Prev {
 7213                buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
 7214            } else {
 7215                buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
 7216            };
 7217            let group = diagnostics.find_map(|entry| {
 7218                if entry.diagnostic.is_primary
 7219                    && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
 7220                    && !entry.range.is_empty()
 7221                    && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
 7222                    && !entry.range.contains(&search_start)
 7223                {
 7224                    Some((entry.range, entry.diagnostic.group_id))
 7225                } else {
 7226                    None
 7227                }
 7228            });
 7229
 7230            if let Some((primary_range, group_id)) = group {
 7231                if self.activate_diagnostics(group_id, cx) {
 7232                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7233                        s.select(vec![Selection {
 7234                            id: selection.id,
 7235                            start: primary_range.start,
 7236                            end: primary_range.start,
 7237                            reversed: false,
 7238                            goal: SelectionGoal::None,
 7239                        }]);
 7240                    });
 7241                }
 7242                break;
 7243            } else {
 7244                // Cycle around to the start of the buffer, potentially moving back to the start of
 7245                // the currently active diagnostic.
 7246                active_primary_range.take();
 7247                if direction == Direction::Prev {
 7248                    if search_start == buffer.len() {
 7249                        break;
 7250                    } else {
 7251                        search_start = buffer.len();
 7252                    }
 7253                } else if search_start == 0 {
 7254                    break;
 7255                } else {
 7256                    search_start = 0;
 7257                }
 7258            }
 7259        }
 7260    }
 7261
 7262    fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
 7263        let snapshot = self
 7264            .display_map
 7265            .update(cx, |display_map, cx| display_map.snapshot(cx));
 7266        let selection = self.selections.newest::<Point>(cx);
 7267
 7268        if !self.seek_in_direction(
 7269            &snapshot,
 7270            selection.head(),
 7271            false,
 7272            snapshot
 7273                .buffer_snapshot
 7274                .git_diff_hunks_in_range((selection.head().row + 1)..u32::MAX),
 7275            cx,
 7276        ) {
 7277            let wrapped_point = Point::zero();
 7278            self.seek_in_direction(
 7279                &snapshot,
 7280                wrapped_point,
 7281                true,
 7282                snapshot
 7283                    .buffer_snapshot
 7284                    .git_diff_hunks_in_range((wrapped_point.row + 1)..u32::MAX),
 7285                cx,
 7286            );
 7287        }
 7288    }
 7289
 7290    fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
 7291        let snapshot = self
 7292            .display_map
 7293            .update(cx, |display_map, cx| display_map.snapshot(cx));
 7294        let selection = self.selections.newest::<Point>(cx);
 7295
 7296        if !self.seek_in_direction(
 7297            &snapshot,
 7298            selection.head(),
 7299            false,
 7300            snapshot
 7301                .buffer_snapshot
 7302                .git_diff_hunks_in_range_rev(0..selection.head().row),
 7303            cx,
 7304        ) {
 7305            let wrapped_point = snapshot.buffer_snapshot.max_point();
 7306            self.seek_in_direction(
 7307                &snapshot,
 7308                wrapped_point,
 7309                true,
 7310                snapshot
 7311                    .buffer_snapshot
 7312                    .git_diff_hunks_in_range_rev(0..wrapped_point.row),
 7313                cx,
 7314            );
 7315        }
 7316    }
 7317
 7318    fn seek_in_direction(
 7319        &mut self,
 7320        snapshot: &DisplaySnapshot,
 7321        initial_point: Point,
 7322        is_wrapped: bool,
 7323        hunks: impl Iterator<Item = DiffHunk<u32>>,
 7324        cx: &mut ViewContext<Editor>,
 7325    ) -> bool {
 7326        let display_point = initial_point.to_display_point(snapshot);
 7327        let mut hunks = hunks
 7328            .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
 7329            .filter(|hunk| {
 7330                if is_wrapped {
 7331                    true
 7332                } else {
 7333                    !hunk.contains_display_row(display_point.row())
 7334                }
 7335            })
 7336            .dedup();
 7337
 7338        if let Some(hunk) = hunks.next() {
 7339            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7340                let row = hunk.start_display_row();
 7341                let point = DisplayPoint::new(row, 0);
 7342                s.select_display_ranges([point..point]);
 7343            });
 7344
 7345            true
 7346        } else {
 7347            false
 7348        }
 7349    }
 7350
 7351    pub fn go_to_definition(&mut self, _: &GoToDefinition, cx: &mut ViewContext<Self>) {
 7352        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx);
 7353    }
 7354
 7355    pub fn go_to_type_definition(&mut self, _: &GoToTypeDefinition, cx: &mut ViewContext<Self>) {
 7356        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx);
 7357    }
 7358
 7359    pub fn go_to_definition_split(&mut self, _: &GoToDefinitionSplit, cx: &mut ViewContext<Self>) {
 7360        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, cx);
 7361    }
 7362
 7363    pub fn go_to_type_definition_split(
 7364        &mut self,
 7365        _: &GoToTypeDefinitionSplit,
 7366        cx: &mut ViewContext<Self>,
 7367    ) {
 7368        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, cx);
 7369    }
 7370
 7371    fn go_to_definition_of_kind(
 7372        &mut self,
 7373        kind: GotoDefinitionKind,
 7374        split: bool,
 7375        cx: &mut ViewContext<Self>,
 7376    ) {
 7377        let Some(workspace) = self.workspace() else {
 7378            return;
 7379        };
 7380        let buffer = self.buffer.read(cx);
 7381        let head = self.selections.newest::<usize>(cx).head();
 7382        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
 7383            text_anchor
 7384        } else {
 7385            return;
 7386        };
 7387
 7388        let project = workspace.read(cx).project().clone();
 7389        let definitions = project.update(cx, |project, cx| match kind {
 7390            GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
 7391            GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
 7392        });
 7393
 7394        cx.spawn(|editor, mut cx| async move {
 7395            let definitions = definitions.await?;
 7396            editor.update(&mut cx, |editor, cx| {
 7397                editor.navigate_to_hover_links(
 7398                    definitions.into_iter().map(HoverLink::Text).collect(),
 7399                    split,
 7400                    cx,
 7401                );
 7402            })?;
 7403            Ok::<(), anyhow::Error>(())
 7404        })
 7405        .detach_and_log_err(cx);
 7406    }
 7407
 7408    pub fn open_url(&mut self, _: &OpenUrl, cx: &mut ViewContext<Self>) {
 7409        let position = self.selections.newest_anchor().head();
 7410        let Some((buffer, buffer_position)) = self
 7411            .buffer
 7412            .read(cx)
 7413            .text_anchor_for_position(position.clone(), cx)
 7414        else {
 7415            return;
 7416        };
 7417
 7418        cx.spawn(|editor, mut cx| async move {
 7419            if let Some((_, url)) = find_url(&buffer, buffer_position, cx.clone()) {
 7420                editor.update(&mut cx, |_, cx| {
 7421                    cx.open_url(&url);
 7422                })
 7423            } else {
 7424                Ok(())
 7425            }
 7426        })
 7427        .detach();
 7428    }
 7429
 7430    pub fn navigate_to_hover_links(
 7431        &mut self,
 7432        mut definitions: Vec<HoverLink>,
 7433        split: bool,
 7434        cx: &mut ViewContext<Editor>,
 7435    ) {
 7436        // If there is one definition, just open it directly
 7437        if definitions.len() == 1 {
 7438            let definition = definitions.pop().unwrap();
 7439            let target_task = match definition {
 7440                HoverLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
 7441                HoverLink::InlayHint(lsp_location, server_id) => {
 7442                    self.compute_target_location(lsp_location, server_id, cx)
 7443                }
 7444                HoverLink::Url(url) => {
 7445                    cx.open_url(&url);
 7446                    Task::ready(Ok(None))
 7447                }
 7448            };
 7449            cx.spawn(|editor, mut cx| async move {
 7450                let target = target_task.await.context("target resolution task")?;
 7451                if let Some(target) = target {
 7452                    editor.update(&mut cx, |editor, cx| {
 7453                        let Some(workspace) = editor.workspace() else {
 7454                            return;
 7455                        };
 7456                        let pane = workspace.read(cx).active_pane().clone();
 7457
 7458                        let range = target.range.to_offset(target.buffer.read(cx));
 7459                        let range = editor.range_for_match(&range);
 7460                        if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
 7461                            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 7462                                s.select_ranges([range]);
 7463                            });
 7464                        } else {
 7465                            cx.window_context().defer(move |cx| {
 7466                                let target_editor: View<Self> =
 7467                                    workspace.update(cx, |workspace, cx| {
 7468                                        if split {
 7469                                            workspace.split_project_item(target.buffer.clone(), cx)
 7470                                        } else {
 7471                                            workspace.open_project_item(target.buffer.clone(), cx)
 7472                                        }
 7473                                    });
 7474                                target_editor.update(cx, |target_editor, cx| {
 7475                                    // When selecting a definition in a different buffer, disable the nav history
 7476                                    // to avoid creating a history entry at the previous cursor location.
 7477                                    pane.update(cx, |pane, _| pane.disable_history());
 7478                                    target_editor.change_selections(
 7479                                        Some(Autoscroll::fit()),
 7480                                        cx,
 7481                                        |s| {
 7482                                            s.select_ranges([range]);
 7483                                        },
 7484                                    );
 7485                                    pane.update(cx, |pane, _| pane.enable_history());
 7486                                });
 7487                            });
 7488                        }
 7489                    })
 7490                } else {
 7491                    Ok(())
 7492                }
 7493            })
 7494            .detach_and_log_err(cx);
 7495        } else if !definitions.is_empty() {
 7496            let replica_id = self.replica_id(cx);
 7497            cx.spawn(|editor, mut cx| async move {
 7498                let (title, location_tasks, workspace) = editor
 7499                    .update(&mut cx, |editor, cx| {
 7500                        let title = definitions
 7501                            .iter()
 7502                            .find_map(|definition| match definition {
 7503                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
 7504                                    let buffer = origin.buffer.read(cx);
 7505                                    format!(
 7506                                        "Definitions for {}",
 7507                                        buffer
 7508                                            .text_for_range(origin.range.clone())
 7509                                            .collect::<String>()
 7510                                    )
 7511                                }),
 7512                                HoverLink::InlayHint(_, _) => None,
 7513                                HoverLink::Url(_) => None,
 7514                            })
 7515                            .unwrap_or("Definitions".to_string());
 7516                        let location_tasks = definitions
 7517                            .into_iter()
 7518                            .map(|definition| match definition {
 7519                                HoverLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
 7520                                HoverLink::InlayHint(lsp_location, server_id) => {
 7521                                    editor.compute_target_location(lsp_location, server_id, cx)
 7522                                }
 7523                                HoverLink::Url(_) => Task::ready(Ok(None)),
 7524                            })
 7525                            .collect::<Vec<_>>();
 7526                        (title, location_tasks, editor.workspace().clone())
 7527                    })
 7528                    .context("location tasks preparation")?;
 7529
 7530                let locations = futures::future::join_all(location_tasks)
 7531                    .await
 7532                    .into_iter()
 7533                    .filter_map(|location| location.transpose())
 7534                    .collect::<Result<_>>()
 7535                    .context("location tasks")?;
 7536
 7537                let Some(workspace) = workspace else {
 7538                    return Ok(());
 7539                };
 7540                workspace
 7541                    .update(&mut cx, |workspace, cx| {
 7542                        Self::open_locations_in_multibuffer(
 7543                            workspace, locations, replica_id, title, split, cx,
 7544                        )
 7545                    })
 7546                    .ok();
 7547
 7548                anyhow::Ok(())
 7549            })
 7550            .detach_and_log_err(cx);
 7551        }
 7552    }
 7553
 7554    fn compute_target_location(
 7555        &self,
 7556        lsp_location: lsp::Location,
 7557        server_id: LanguageServerId,
 7558        cx: &mut ViewContext<Editor>,
 7559    ) -> Task<anyhow::Result<Option<Location>>> {
 7560        let Some(project) = self.project.clone() else {
 7561            return Task::Ready(Some(Ok(None)));
 7562        };
 7563
 7564        cx.spawn(move |editor, mut cx| async move {
 7565            let location_task = editor.update(&mut cx, |editor, cx| {
 7566                project.update(cx, |project, cx| {
 7567                    let language_server_name =
 7568                        editor.buffer.read(cx).as_singleton().and_then(|buffer| {
 7569                            project
 7570                                .language_server_for_buffer(buffer.read(cx), server_id, cx)
 7571                                .map(|(lsp_adapter, _)| lsp_adapter.name.clone())
 7572                        });
 7573                    language_server_name.map(|language_server_name| {
 7574                        project.open_local_buffer_via_lsp(
 7575                            lsp_location.uri.clone(),
 7576                            server_id,
 7577                            language_server_name,
 7578                            cx,
 7579                        )
 7580                    })
 7581                })
 7582            })?;
 7583            let location = match location_task {
 7584                Some(task) => Some({
 7585                    let target_buffer_handle = task.await.context("open local buffer")?;
 7586                    let range = target_buffer_handle.update(&mut cx, |target_buffer, _| {
 7587                        let target_start = target_buffer
 7588                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
 7589                        let target_end = target_buffer
 7590                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
 7591                        target_buffer.anchor_after(target_start)
 7592                            ..target_buffer.anchor_before(target_end)
 7593                    })?;
 7594                    Location {
 7595                        buffer: target_buffer_handle,
 7596                        range,
 7597                    }
 7598                }),
 7599                None => None,
 7600            };
 7601            Ok(location)
 7602        })
 7603    }
 7604
 7605    pub fn find_all_references(
 7606        &mut self,
 7607        _: &FindAllReferences,
 7608        cx: &mut ViewContext<Self>,
 7609    ) -> Option<Task<Result<()>>> {
 7610        let buffer = self.buffer.read(cx);
 7611        let head = self.selections.newest::<usize>(cx).head();
 7612        let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
 7613        let replica_id = self.replica_id(cx);
 7614
 7615        let workspace = self.workspace()?;
 7616        let project = workspace.read(cx).project().clone();
 7617        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
 7618        Some(cx.spawn(|_, mut cx| async move {
 7619            let locations = references.await?;
 7620            if locations.is_empty() {
 7621                return Ok(());
 7622            }
 7623
 7624            workspace.update(&mut cx, |workspace, cx| {
 7625                let title = locations
 7626                    .first()
 7627                    .as_ref()
 7628                    .map(|location| {
 7629                        let buffer = location.buffer.read(cx);
 7630                        format!(
 7631                            "References to `{}`",
 7632                            buffer
 7633                                .text_for_range(location.range.clone())
 7634                                .collect::<String>()
 7635                        )
 7636                    })
 7637                    .unwrap();
 7638                Self::open_locations_in_multibuffer(
 7639                    workspace, locations, replica_id, title, false, cx,
 7640                );
 7641            })?;
 7642
 7643            Ok(())
 7644        }))
 7645    }
 7646
 7647    /// Opens a multibuffer with the given project locations in it
 7648    pub fn open_locations_in_multibuffer(
 7649        workspace: &mut Workspace,
 7650        mut locations: Vec<Location>,
 7651        replica_id: ReplicaId,
 7652        title: String,
 7653        split: bool,
 7654        cx: &mut ViewContext<Workspace>,
 7655    ) {
 7656        // If there are multiple definitions, open them in a multibuffer
 7657        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
 7658        let mut locations = locations.into_iter().peekable();
 7659        let mut ranges_to_highlight = Vec::new();
 7660        let capability = workspace.project().read(cx).capability();
 7661
 7662        let excerpt_buffer = cx.new_model(|cx| {
 7663            let mut multibuffer = MultiBuffer::new(replica_id, capability);
 7664            while let Some(location) = locations.next() {
 7665                let buffer = location.buffer.read(cx);
 7666                let mut ranges_for_buffer = Vec::new();
 7667                let range = location.range.to_offset(buffer);
 7668                ranges_for_buffer.push(range.clone());
 7669
 7670                while let Some(next_location) = locations.peek() {
 7671                    if next_location.buffer == location.buffer {
 7672                        ranges_for_buffer.push(next_location.range.to_offset(buffer));
 7673                        locations.next();
 7674                    } else {
 7675                        break;
 7676                    }
 7677                }
 7678
 7679                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
 7680                ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
 7681                    location.buffer.clone(),
 7682                    ranges_for_buffer,
 7683                    1,
 7684                    cx,
 7685                ))
 7686            }
 7687
 7688            multibuffer.with_title(title)
 7689        });
 7690
 7691        let editor = cx.new_view(|cx| {
 7692            Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
 7693        });
 7694        editor.update(cx, |editor, cx| {
 7695            editor.highlight_background::<Self>(
 7696                ranges_to_highlight,
 7697                |theme| theme.editor_highlighted_line_background,
 7698                cx,
 7699            );
 7700        });
 7701        if split {
 7702            workspace.split_item(SplitDirection::Right, Box::new(editor), cx);
 7703        } else {
 7704            workspace.add_item(Box::new(editor), cx);
 7705        }
 7706    }
 7707
 7708    pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
 7709        use language::ToOffset as _;
 7710
 7711        let project = self.project.clone()?;
 7712        let selection = self.selections.newest_anchor().clone();
 7713        let (cursor_buffer, cursor_buffer_position) = self
 7714            .buffer
 7715            .read(cx)
 7716            .text_anchor_for_position(selection.head(), cx)?;
 7717        let (tail_buffer, _) = self
 7718            .buffer
 7719            .read(cx)
 7720            .text_anchor_for_position(selection.tail(), cx)?;
 7721        if tail_buffer != cursor_buffer {
 7722            return None;
 7723        }
 7724
 7725        let snapshot = cursor_buffer.read(cx).snapshot();
 7726        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
 7727        let prepare_rename = project.update(cx, |project, cx| {
 7728            project.prepare_rename(cursor_buffer.clone(), cursor_buffer_offset, cx)
 7729        });
 7730        drop(snapshot);
 7731
 7732        Some(cx.spawn(|this, mut cx| async move {
 7733            let rename_range = if let Some(range) = prepare_rename.await? {
 7734                Some(range)
 7735            } else {
 7736                this.update(&mut cx, |this, cx| {
 7737                    let buffer = this.buffer.read(cx).snapshot(cx);
 7738                    let mut buffer_highlights = this
 7739                        .document_highlights_for_position(selection.head(), &buffer)
 7740                        .filter(|highlight| {
 7741                            highlight.start.excerpt_id == selection.head().excerpt_id
 7742                                && highlight.end.excerpt_id == selection.head().excerpt_id
 7743                        });
 7744                    buffer_highlights
 7745                        .next()
 7746                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
 7747                })?
 7748            };
 7749            if let Some(rename_range) = rename_range {
 7750                this.update(&mut cx, |this, cx| {
 7751                    let snapshot = cursor_buffer.read(cx).snapshot();
 7752                    let rename_buffer_range = rename_range.to_offset(&snapshot);
 7753                    let cursor_offset_in_rename_range =
 7754                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
 7755
 7756                    this.take_rename(false, cx);
 7757                    let buffer = this.buffer.read(cx).read(cx);
 7758                    let cursor_offset = selection.head().to_offset(&buffer);
 7759                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
 7760                    let rename_end = rename_start + rename_buffer_range.len();
 7761                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
 7762                    let mut old_highlight_id = None;
 7763                    let old_name: Arc<str> = buffer
 7764                        .chunks(rename_start..rename_end, true)
 7765                        .map(|chunk| {
 7766                            if old_highlight_id.is_none() {
 7767                                old_highlight_id = chunk.syntax_highlight_id;
 7768                            }
 7769                            chunk.text
 7770                        })
 7771                        .collect::<String>()
 7772                        .into();
 7773
 7774                    drop(buffer);
 7775
 7776                    // Position the selection in the rename editor so that it matches the current selection.
 7777                    this.show_local_selections = false;
 7778                    let rename_editor = cx.new_view(|cx| {
 7779                        let mut editor = Editor::single_line(cx);
 7780                        editor.buffer.update(cx, |buffer, cx| {
 7781                            buffer.edit([(0..0, old_name.clone())], None, cx)
 7782                        });
 7783                        editor.select_all(&SelectAll, cx);
 7784                        editor
 7785                    });
 7786
 7787                    let ranges = this
 7788                        .clear_background_highlights::<DocumentHighlightWrite>(cx)
 7789                        .into_iter()
 7790                        .flat_map(|(_, ranges)| ranges.into_iter())
 7791                        .chain(
 7792                            this.clear_background_highlights::<DocumentHighlightRead>(cx)
 7793                                .into_iter()
 7794                                .flat_map(|(_, ranges)| ranges.into_iter()),
 7795                        )
 7796                        .collect();
 7797
 7798                    this.highlight_text::<Rename>(
 7799                        ranges,
 7800                        HighlightStyle {
 7801                            fade_out: Some(0.6),
 7802                            ..Default::default()
 7803                        },
 7804                        cx,
 7805                    );
 7806                    let rename_focus_handle = rename_editor.focus_handle(cx);
 7807                    cx.focus(&rename_focus_handle);
 7808                    let block_id = this.insert_blocks(
 7809                        [BlockProperties {
 7810                            style: BlockStyle::Flex,
 7811                            position: range.start.clone(),
 7812                            height: 1,
 7813                            render: Arc::new({
 7814                                let rename_editor = rename_editor.clone();
 7815                                move |cx: &mut BlockContext| {
 7816                                    let mut text_style = cx.editor_style.text.clone();
 7817                                    if let Some(highlight_style) = old_highlight_id
 7818                                        .and_then(|h| h.style(&cx.editor_style.syntax))
 7819                                    {
 7820                                        text_style = text_style.highlight(highlight_style);
 7821                                    }
 7822                                    div()
 7823                                        .pl(cx.anchor_x)
 7824                                        .child(EditorElement::new(
 7825                                            &rename_editor,
 7826                                            EditorStyle {
 7827                                                background: cx.theme().system().transparent,
 7828                                                local_player: cx.editor_style.local_player,
 7829                                                text: text_style,
 7830                                                scrollbar_width: cx.editor_style.scrollbar_width,
 7831                                                syntax: cx.editor_style.syntax.clone(),
 7832                                                status: cx.editor_style.status.clone(),
 7833                                                inlays_style: HighlightStyle {
 7834                                                    color: Some(cx.theme().status().hint),
 7835                                                    font_weight: Some(FontWeight::BOLD),
 7836                                                    ..HighlightStyle::default()
 7837                                                },
 7838                                                suggestions_style: HighlightStyle {
 7839                                                    color: Some(cx.theme().status().predictive),
 7840                                                    ..HighlightStyle::default()
 7841                                                },
 7842                                            },
 7843                                        ))
 7844                                        .into_any_element()
 7845                                }
 7846                            }),
 7847                            disposition: BlockDisposition::Below,
 7848                        }],
 7849                        Some(Autoscroll::fit()),
 7850                        cx,
 7851                    )[0];
 7852                    this.pending_rename = Some(RenameState {
 7853                        range,
 7854                        old_name,
 7855                        editor: rename_editor,
 7856                        block_id,
 7857                    });
 7858                })?;
 7859            }
 7860
 7861            Ok(())
 7862        }))
 7863    }
 7864
 7865    pub fn confirm_rename(
 7866        &mut self,
 7867        _: &ConfirmRename,
 7868        cx: &mut ViewContext<Self>,
 7869    ) -> Option<Task<Result<()>>> {
 7870        let rename = self.take_rename(false, cx)?;
 7871        let workspace = self.workspace()?;
 7872        let (start_buffer, start) = self
 7873            .buffer
 7874            .read(cx)
 7875            .text_anchor_for_position(rename.range.start.clone(), cx)?;
 7876        let (end_buffer, end) = self
 7877            .buffer
 7878            .read(cx)
 7879            .text_anchor_for_position(rename.range.end.clone(), cx)?;
 7880        if start_buffer != end_buffer {
 7881            return None;
 7882        }
 7883
 7884        let buffer = start_buffer;
 7885        let range = start..end;
 7886        let old_name = rename.old_name;
 7887        let new_name = rename.editor.read(cx).text(cx);
 7888
 7889        let rename = workspace
 7890            .read(cx)
 7891            .project()
 7892            .clone()
 7893            .update(cx, |project, cx| {
 7894                project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
 7895            });
 7896        let workspace = workspace.downgrade();
 7897
 7898        Some(cx.spawn(|editor, mut cx| async move {
 7899            let project_transaction = rename.await?;
 7900            Self::open_project_transaction(
 7901                &editor,
 7902                workspace,
 7903                project_transaction,
 7904                format!("Rename: {}{}", old_name, new_name),
 7905                cx.clone(),
 7906            )
 7907            .await?;
 7908
 7909            editor.update(&mut cx, |editor, cx| {
 7910                editor.refresh_document_highlights(cx);
 7911            })?;
 7912            Ok(())
 7913        }))
 7914    }
 7915
 7916    fn take_rename(
 7917        &mut self,
 7918        moving_cursor: bool,
 7919        cx: &mut ViewContext<Self>,
 7920    ) -> Option<RenameState> {
 7921        let rename = self.pending_rename.take()?;
 7922        if rename.editor.focus_handle(cx).is_focused(cx) {
 7923            cx.focus(&self.focus_handle);
 7924        }
 7925
 7926        self.remove_blocks(
 7927            [rename.block_id].into_iter().collect(),
 7928            Some(Autoscroll::fit()),
 7929            cx,
 7930        );
 7931        self.clear_highlights::<Rename>(cx);
 7932        self.show_local_selections = true;
 7933
 7934        if moving_cursor {
 7935            let rename_editor = rename.editor.read(cx);
 7936            let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
 7937
 7938            // Update the selection to match the position of the selection inside
 7939            // the rename editor.
 7940            let snapshot = self.buffer.read(cx).read(cx);
 7941            let rename_range = rename.range.to_offset(&snapshot);
 7942            let cursor_in_editor = snapshot
 7943                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
 7944                .min(rename_range.end);
 7945            drop(snapshot);
 7946
 7947            self.change_selections(None, cx, |s| {
 7948                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
 7949            });
 7950        } else {
 7951            self.refresh_document_highlights(cx);
 7952        }
 7953
 7954        Some(rename)
 7955    }
 7956
 7957    pub fn pending_rename(&self) -> Option<&RenameState> {
 7958        self.pending_rename.as_ref()
 7959    }
 7960
 7961    fn format(&mut self, _: &Format, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
 7962        let project = match &self.project {
 7963            Some(project) => project.clone(),
 7964            None => return None,
 7965        };
 7966
 7967        Some(self.perform_format(project, FormatTrigger::Manual, cx))
 7968    }
 7969
 7970    fn perform_format(
 7971        &mut self,
 7972        project: Model<Project>,
 7973        trigger: FormatTrigger,
 7974        cx: &mut ViewContext<Self>,
 7975    ) -> Task<Result<()>> {
 7976        let buffer = self.buffer().clone();
 7977        let buffers = buffer.read(cx).all_buffers();
 7978
 7979        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
 7980        let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
 7981
 7982        cx.spawn(|_, mut cx| async move {
 7983            let transaction = futures::select_biased! {
 7984                _ = timeout => {
 7985                    log::warn!("timed out waiting for formatting");
 7986                    None
 7987                }
 7988                transaction = format.log_err().fuse() => transaction,
 7989            };
 7990
 7991            buffer
 7992                .update(&mut cx, |buffer, cx| {
 7993                    if let Some(transaction) = transaction {
 7994                        if !buffer.is_singleton() {
 7995                            buffer.push_transaction(&transaction.0, cx);
 7996                        }
 7997                    }
 7998
 7999                    cx.notify();
 8000                })
 8001                .ok();
 8002
 8003            Ok(())
 8004        })
 8005    }
 8006
 8007    fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
 8008        if let Some(project) = self.project.clone() {
 8009            self.buffer.update(cx, |multi_buffer, cx| {
 8010                project.update(cx, |project, cx| {
 8011                    project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
 8012                });
 8013            })
 8014        }
 8015    }
 8016
 8017    fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
 8018        cx.show_character_palette();
 8019    }
 8020
 8021    fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
 8022        if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
 8023            let buffer = self.buffer.read(cx).snapshot(cx);
 8024            let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
 8025            let is_valid = buffer
 8026                .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
 8027                .any(|entry| {
 8028                    entry.diagnostic.is_primary
 8029                        && !entry.range.is_empty()
 8030                        && entry.range.start == primary_range_start
 8031                        && entry.diagnostic.message == active_diagnostics.primary_message
 8032                });
 8033
 8034            if is_valid != active_diagnostics.is_valid {
 8035                active_diagnostics.is_valid = is_valid;
 8036                let mut new_styles = HashMap::default();
 8037                for (block_id, diagnostic) in &active_diagnostics.blocks {
 8038                    new_styles.insert(
 8039                        *block_id,
 8040                        diagnostic_block_renderer(diagnostic.clone(), is_valid),
 8041                    );
 8042                }
 8043                self.display_map
 8044                    .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
 8045            }
 8046        }
 8047    }
 8048
 8049    fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
 8050        self.dismiss_diagnostics(cx);
 8051        self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
 8052            let buffer = self.buffer.read(cx).snapshot(cx);
 8053
 8054            let mut primary_range = None;
 8055            let mut primary_message = None;
 8056            let mut group_end = Point::zero();
 8057            let diagnostic_group = buffer
 8058                .diagnostic_group::<Point>(group_id)
 8059                .map(|entry| {
 8060                    if entry.range.end > group_end {
 8061                        group_end = entry.range.end;
 8062                    }
 8063                    if entry.diagnostic.is_primary {
 8064                        primary_range = Some(entry.range.clone());
 8065                        primary_message = Some(entry.diagnostic.message.clone());
 8066                    }
 8067                    entry
 8068                })
 8069                .collect::<Vec<_>>();
 8070            let primary_range = primary_range?;
 8071            let primary_message = primary_message?;
 8072            let primary_range =
 8073                buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
 8074
 8075            let blocks = display_map
 8076                .insert_blocks(
 8077                    diagnostic_group.iter().map(|entry| {
 8078                        let diagnostic = entry.diagnostic.clone();
 8079                        let message_height = diagnostic.message.matches('\n').count() as u8 + 1;
 8080                        BlockProperties {
 8081                            style: BlockStyle::Fixed,
 8082                            position: buffer.anchor_after(entry.range.start),
 8083                            height: message_height,
 8084                            render: diagnostic_block_renderer(diagnostic, true),
 8085                            disposition: BlockDisposition::Below,
 8086                        }
 8087                    }),
 8088                    cx,
 8089                )
 8090                .into_iter()
 8091                .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
 8092                .collect();
 8093
 8094            Some(ActiveDiagnosticGroup {
 8095                primary_range,
 8096                primary_message,
 8097                blocks,
 8098                is_valid: true,
 8099            })
 8100        });
 8101        self.active_diagnostics.is_some()
 8102    }
 8103
 8104    fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
 8105        if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
 8106            self.display_map.update(cx, |display_map, cx| {
 8107                display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
 8108            });
 8109            cx.notify();
 8110        }
 8111    }
 8112
 8113    pub fn set_selections_from_remote(
 8114        &mut self,
 8115        selections: Vec<Selection<Anchor>>,
 8116        pending_selection: Option<Selection<Anchor>>,
 8117        cx: &mut ViewContext<Self>,
 8118    ) {
 8119        let old_cursor_position = self.selections.newest_anchor().head();
 8120        self.selections.change_with(cx, |s| {
 8121            s.select_anchors(selections);
 8122            if let Some(pending_selection) = pending_selection {
 8123                s.set_pending(pending_selection, SelectMode::Character);
 8124            } else {
 8125                s.clear_pending();
 8126            }
 8127        });
 8128        self.selections_did_change(false, &old_cursor_position, cx);
 8129    }
 8130
 8131    fn push_to_selection_history(&mut self) {
 8132        self.selection_history.push(SelectionHistoryEntry {
 8133            selections: self.selections.disjoint_anchors(),
 8134            select_next_state: self.select_next_state.clone(),
 8135            select_prev_state: self.select_prev_state.clone(),
 8136            add_selections_state: self.add_selections_state.clone(),
 8137        });
 8138    }
 8139
 8140    pub fn transact(
 8141        &mut self,
 8142        cx: &mut ViewContext<Self>,
 8143        update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
 8144    ) -> Option<TransactionId> {
 8145        self.start_transaction_at(Instant::now(), cx);
 8146        update(self, cx);
 8147        self.end_transaction_at(Instant::now(), cx)
 8148    }
 8149
 8150    fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
 8151        self.end_selection(cx);
 8152        if let Some(tx_id) = self
 8153            .buffer
 8154            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
 8155        {
 8156            self.selection_history
 8157                .insert_transaction(tx_id, self.selections.disjoint_anchors());
 8158        }
 8159    }
 8160
 8161    fn end_transaction_at(
 8162        &mut self,
 8163        now: Instant,
 8164        cx: &mut ViewContext<Self>,
 8165    ) -> Option<TransactionId> {
 8166        if let Some(tx_id) = self
 8167            .buffer
 8168            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
 8169        {
 8170            if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
 8171                *end_selections = Some(self.selections.disjoint_anchors());
 8172            } else {
 8173                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
 8174            }
 8175
 8176            cx.emit(EditorEvent::Edited);
 8177            Some(tx_id)
 8178        } else {
 8179            None
 8180        }
 8181    }
 8182
 8183    pub fn fold(&mut self, _: &actions::Fold, cx: &mut ViewContext<Self>) {
 8184        let mut fold_ranges = Vec::new();
 8185
 8186        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8187
 8188        let selections = self.selections.all_adjusted(cx);
 8189        for selection in selections {
 8190            let range = selection.range().sorted();
 8191            let buffer_start_row = range.start.row;
 8192
 8193            for row in (0..=range.end.row).rev() {
 8194                let fold_range = display_map.foldable_range(row);
 8195
 8196                if let Some(fold_range) = fold_range {
 8197                    if fold_range.end.row >= buffer_start_row {
 8198                        fold_ranges.push(fold_range);
 8199                        if row <= range.start.row {
 8200                            break;
 8201                        }
 8202                    }
 8203                }
 8204            }
 8205        }
 8206
 8207        self.fold_ranges(fold_ranges, true, cx);
 8208    }
 8209
 8210    pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
 8211        let buffer_row = fold_at.buffer_row;
 8212        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8213
 8214        if let Some(fold_range) = display_map.foldable_range(buffer_row) {
 8215            let autoscroll = self
 8216                .selections
 8217                .all::<Point>(cx)
 8218                .iter()
 8219                .any(|selection| fold_range.overlaps(&selection.range()));
 8220
 8221            self.fold_ranges(std::iter::once(fold_range), autoscroll, cx);
 8222        }
 8223    }
 8224
 8225    pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
 8226        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8227        let buffer = &display_map.buffer_snapshot;
 8228        let selections = self.selections.all::<Point>(cx);
 8229        let ranges = selections
 8230            .iter()
 8231            .map(|s| {
 8232                let range = s.display_range(&display_map).sorted();
 8233                let mut start = range.start.to_point(&display_map);
 8234                let mut end = range.end.to_point(&display_map);
 8235                start.column = 0;
 8236                end.column = buffer.line_len(end.row);
 8237                start..end
 8238            })
 8239            .collect::<Vec<_>>();
 8240
 8241        self.unfold_ranges(ranges, true, true, cx);
 8242    }
 8243
 8244    pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
 8245        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8246
 8247        let intersection_range = Point::new(unfold_at.buffer_row, 0)
 8248            ..Point::new(
 8249                unfold_at.buffer_row,
 8250                display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
 8251            );
 8252
 8253        let autoscroll = self
 8254            .selections
 8255            .all::<Point>(cx)
 8256            .iter()
 8257            .any(|selection| selection.range().overlaps(&intersection_range));
 8258
 8259        self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx)
 8260    }
 8261
 8262    pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
 8263        let selections = self.selections.all::<Point>(cx);
 8264        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 8265        let line_mode = self.selections.line_mode;
 8266        let ranges = selections.into_iter().map(|s| {
 8267            if line_mode {
 8268                let start = Point::new(s.start.row, 0);
 8269                let end = Point::new(s.end.row, display_map.buffer_snapshot.line_len(s.end.row));
 8270                start..end
 8271            } else {
 8272                s.start..s.end
 8273            }
 8274        });
 8275        self.fold_ranges(ranges, true, cx);
 8276    }
 8277
 8278    pub fn fold_ranges<T: ToOffset + Clone>(
 8279        &mut self,
 8280        ranges: impl IntoIterator<Item = Range<T>>,
 8281        auto_scroll: bool,
 8282        cx: &mut ViewContext<Self>,
 8283    ) {
 8284        let mut ranges = ranges.into_iter().peekable();
 8285        if ranges.peek().is_some() {
 8286            self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
 8287
 8288            if auto_scroll {
 8289                self.request_autoscroll(Autoscroll::fit(), cx);
 8290            }
 8291
 8292            cx.notify();
 8293        }
 8294    }
 8295
 8296    pub fn unfold_ranges<T: ToOffset + Clone>(
 8297        &mut self,
 8298        ranges: impl IntoIterator<Item = Range<T>>,
 8299        inclusive: bool,
 8300        auto_scroll: bool,
 8301        cx: &mut ViewContext<Self>,
 8302    ) {
 8303        let mut ranges = ranges.into_iter().peekable();
 8304        if ranges.peek().is_some() {
 8305            self.display_map
 8306                .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
 8307            if auto_scroll {
 8308                self.request_autoscroll(Autoscroll::fit(), cx);
 8309            }
 8310
 8311            cx.notify();
 8312        }
 8313    }
 8314
 8315    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut ViewContext<Self>) {
 8316        if hovered != self.gutter_hovered {
 8317            self.gutter_hovered = hovered;
 8318            cx.notify();
 8319        }
 8320    }
 8321
 8322    pub fn insert_blocks(
 8323        &mut self,
 8324        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
 8325        autoscroll: Option<Autoscroll>,
 8326        cx: &mut ViewContext<Self>,
 8327    ) -> Vec<BlockId> {
 8328        let blocks = self
 8329            .display_map
 8330            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
 8331        if let Some(autoscroll) = autoscroll {
 8332            self.request_autoscroll(autoscroll, cx);
 8333        }
 8334        blocks
 8335    }
 8336
 8337    pub fn replace_blocks(
 8338        &mut self,
 8339        blocks: HashMap<BlockId, RenderBlock>,
 8340        autoscroll: Option<Autoscroll>,
 8341        cx: &mut ViewContext<Self>,
 8342    ) {
 8343        self.display_map
 8344            .update(cx, |display_map, _| display_map.replace_blocks(blocks));
 8345        if let Some(autoscroll) = autoscroll {
 8346            self.request_autoscroll(autoscroll, cx);
 8347        }
 8348    }
 8349
 8350    pub fn remove_blocks(
 8351        &mut self,
 8352        block_ids: HashSet<BlockId>,
 8353        autoscroll: Option<Autoscroll>,
 8354        cx: &mut ViewContext<Self>,
 8355    ) {
 8356        self.display_map.update(cx, |display_map, cx| {
 8357            display_map.remove_blocks(block_ids, cx)
 8358        });
 8359        if let Some(autoscroll) = autoscroll {
 8360            self.request_autoscroll(autoscroll, cx);
 8361        }
 8362    }
 8363
 8364    pub fn longest_row(&self, cx: &mut AppContext) -> u32 {
 8365        self.display_map
 8366            .update(cx, |map, cx| map.snapshot(cx))
 8367            .longest_row()
 8368    }
 8369
 8370    pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint {
 8371        self.display_map
 8372            .update(cx, |map, cx| map.snapshot(cx))
 8373            .max_point()
 8374    }
 8375
 8376    pub fn text(&self, cx: &AppContext) -> String {
 8377        self.buffer.read(cx).read(cx).text()
 8378    }
 8379
 8380    pub fn text_option(&self, cx: &AppContext) -> Option<String> {
 8381        let text = self.text(cx);
 8382        let text = text.trim();
 8383
 8384        if text.is_empty() {
 8385            return None;
 8386        }
 8387
 8388        Some(text.to_string())
 8389    }
 8390
 8391    pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
 8392        self.transact(cx, |this, cx| {
 8393            this.buffer
 8394                .read(cx)
 8395                .as_singleton()
 8396                .expect("you can only call set_text on editors for singleton buffers")
 8397                .update(cx, |buffer, cx| buffer.set_text(text, cx));
 8398        });
 8399    }
 8400
 8401    pub fn display_text(&self, cx: &mut AppContext) -> String {
 8402        self.display_map
 8403            .update(cx, |map, cx| map.snapshot(cx))
 8404            .text()
 8405    }
 8406
 8407    pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> {
 8408        let mut wrap_guides = smallvec::smallvec![];
 8409
 8410        if self.show_wrap_guides == Some(false) {
 8411            return wrap_guides;
 8412        }
 8413
 8414        let settings = self.buffer.read(cx).settings_at(0, cx);
 8415        if settings.show_wrap_guides {
 8416            if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
 8417                wrap_guides.push((soft_wrap as usize, true));
 8418            }
 8419            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
 8420        }
 8421
 8422        wrap_guides
 8423    }
 8424
 8425    pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
 8426        let settings = self.buffer.read(cx).settings_at(0, cx);
 8427        let mode = self
 8428            .soft_wrap_mode_override
 8429            .unwrap_or_else(|| settings.soft_wrap);
 8430        match mode {
 8431            language_settings::SoftWrap::None => SoftWrap::None,
 8432            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
 8433            language_settings::SoftWrap::PreferredLineLength => {
 8434                SoftWrap::Column(settings.preferred_line_length)
 8435            }
 8436        }
 8437    }
 8438
 8439    pub fn set_soft_wrap_mode(
 8440        &mut self,
 8441        mode: language_settings::SoftWrap,
 8442        cx: &mut ViewContext<Self>,
 8443    ) {
 8444        self.soft_wrap_mode_override = Some(mode);
 8445        cx.notify();
 8446    }
 8447
 8448    pub fn set_style(&mut self, style: EditorStyle, cx: &mut ViewContext<Self>) {
 8449        let rem_size = cx.rem_size();
 8450        self.display_map.update(cx, |map, cx| {
 8451            map.set_font(
 8452                style.text.font(),
 8453                style.text.font_size.to_pixels(rem_size),
 8454                cx,
 8455            )
 8456        });
 8457        self.style = Some(style);
 8458    }
 8459
 8460    #[cfg(any(test, feature = "test-support"))]
 8461    pub fn style(&self) -> Option<&EditorStyle> {
 8462        self.style.as_ref()
 8463    }
 8464
 8465    // Called by the element. This method is not designed to be called outside of the editor
 8466    // element's layout code because it does not notify when rewrapping is computed synchronously.
 8467    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut AppContext) -> bool {
 8468        self.display_map
 8469            .update(cx, |map, cx| map.set_wrap_width(width, cx))
 8470    }
 8471
 8472    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
 8473        if self.soft_wrap_mode_override.is_some() {
 8474            self.soft_wrap_mode_override.take();
 8475        } else {
 8476            let soft_wrap = match self.soft_wrap_mode(cx) {
 8477                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
 8478                SoftWrap::EditorWidth | SoftWrap::Column(_) => language_settings::SoftWrap::None,
 8479            };
 8480            self.soft_wrap_mode_override = Some(soft_wrap);
 8481        }
 8482        cx.notify();
 8483    }
 8484
 8485    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
 8486        self.show_gutter = show_gutter;
 8487        cx.notify();
 8488    }
 8489
 8490    pub fn set_show_wrap_guides(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
 8491        self.show_wrap_guides = Some(show_gutter);
 8492        cx.notify();
 8493    }
 8494
 8495    pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
 8496        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
 8497            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
 8498                cx.reveal_path(&file.abs_path(cx));
 8499            }
 8500        }
 8501    }
 8502
 8503    pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
 8504        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
 8505            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
 8506                if let Some(path) = file.abs_path(cx).to_str() {
 8507                    cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
 8508                }
 8509            }
 8510        }
 8511    }
 8512
 8513    pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
 8514        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
 8515            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
 8516                if let Some(path) = file.path().to_str() {
 8517                    cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
 8518                }
 8519            }
 8520        }
 8521    }
 8522
 8523    fn get_permalink_to_line(&mut self, cx: &mut ViewContext<Self>) -> Result<url::Url> {
 8524        use git::permalink::{build_permalink, BuildPermalinkParams};
 8525
 8526        let project = self.project.clone().ok_or_else(|| anyhow!("no project"))?;
 8527        let project = project.read(cx);
 8528
 8529        let worktree = project
 8530            .visible_worktrees(cx)
 8531            .next()
 8532            .ok_or_else(|| anyhow!("no worktree"))?;
 8533
 8534        let mut cwd = worktree.read(cx).abs_path().to_path_buf();
 8535        cwd.push(".git");
 8536
 8537        const REMOTE_NAME: &'static str = "origin";
 8538        let repo = project
 8539            .fs()
 8540            .open_repo(&cwd)
 8541            .ok_or_else(|| anyhow!("no Git repo"))?;
 8542        let origin_url = repo
 8543            .lock()
 8544            .remote_url(REMOTE_NAME)
 8545            .ok_or_else(|| anyhow!("remote \"{REMOTE_NAME}\" not found"))?;
 8546        let sha = repo
 8547            .lock()
 8548            .head_sha()
 8549            .ok_or_else(|| anyhow!("failed to read HEAD SHA"))?;
 8550
 8551        let path = maybe!({
 8552            let buffer = self.buffer().read(cx).as_singleton()?;
 8553            let file = buffer.read(cx).file().and_then(|f| f.as_local())?;
 8554            file.path().to_str().map(|path| path.to_string())
 8555        })
 8556        .ok_or_else(|| anyhow!("failed to determine file path"))?;
 8557
 8558        let selections = self.selections.all::<Point>(cx);
 8559        let selection = selections.iter().peekable().next();
 8560
 8561        build_permalink(BuildPermalinkParams {
 8562            remote_url: &origin_url,
 8563            sha: &sha,
 8564            path: &path,
 8565            selection: selection.map(|selection| selection.range()),
 8566        })
 8567    }
 8568
 8569    pub fn copy_permalink_to_line(&mut self, _: &CopyPermalinkToLine, cx: &mut ViewContext<Self>) {
 8570        let permalink = self.get_permalink_to_line(cx);
 8571
 8572        match permalink {
 8573            Ok(permalink) => {
 8574                cx.write_to_clipboard(ClipboardItem::new(permalink.to_string()));
 8575            }
 8576            Err(err) => {
 8577                let message = format!("Failed to copy permalink: {err}");
 8578
 8579                Err::<(), anyhow::Error>(err).log_err();
 8580
 8581                if let Some(workspace) = self.workspace() {
 8582                    workspace.update(cx, |workspace, cx| {
 8583                        workspace.show_toast(Toast::new(0x156a5f9ee, message), cx)
 8584                    })
 8585                }
 8586            }
 8587        }
 8588    }
 8589
 8590    pub fn open_permalink_to_line(&mut self, _: &OpenPermalinkToLine, cx: &mut ViewContext<Self>) {
 8591        let permalink = self.get_permalink_to_line(cx);
 8592
 8593        match permalink {
 8594            Ok(permalink) => {
 8595                cx.open_url(&permalink.to_string());
 8596            }
 8597            Err(err) => {
 8598                let message = format!("Failed to open permalink: {err}");
 8599
 8600                Err::<(), anyhow::Error>(err).log_err();
 8601
 8602                if let Some(workspace) = self.workspace() {
 8603                    workspace.update(cx, |workspace, cx| {
 8604                        workspace.show_toast(Toast::new(0x45a8978, message), cx)
 8605                    })
 8606                }
 8607            }
 8608        }
 8609    }
 8610
 8611    pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
 8612        self.highlighted_rows = rows;
 8613    }
 8614
 8615    pub fn highlighted_rows(&self) -> Option<Range<u32>> {
 8616        self.highlighted_rows.clone()
 8617    }
 8618
 8619    pub fn highlight_background<T: 'static>(
 8620        &mut self,
 8621        ranges: Vec<Range<Anchor>>,
 8622        color_fetcher: fn(&ThemeColors) -> Hsla,
 8623        cx: &mut ViewContext<Self>,
 8624    ) {
 8625        let snapshot = self.snapshot(cx);
 8626        // this is to try and catch a panic sooner
 8627        for range in &ranges {
 8628            snapshot
 8629                .buffer_snapshot
 8630                .summary_for_anchor::<usize>(&range.start);
 8631            snapshot
 8632                .buffer_snapshot
 8633                .summary_for_anchor::<usize>(&range.end);
 8634        }
 8635
 8636        self.background_highlights
 8637            .insert(TypeId::of::<T>(), (color_fetcher, ranges));
 8638        cx.notify();
 8639    }
 8640
 8641    pub(crate) fn highlight_inlay_background<T: 'static>(
 8642        &mut self,
 8643        ranges: Vec<InlayHighlight>,
 8644        color_fetcher: fn(&ThemeColors) -> Hsla,
 8645        cx: &mut ViewContext<Self>,
 8646    ) {
 8647        // TODO: no actual highlights happen for inlays currently, find a way to do that
 8648        self.inlay_background_highlights
 8649            .insert(Some(TypeId::of::<T>()), (color_fetcher, ranges));
 8650        cx.notify();
 8651    }
 8652
 8653    pub fn clear_background_highlights<T: 'static>(
 8654        &mut self,
 8655        cx: &mut ViewContext<Self>,
 8656    ) -> Option<BackgroundHighlight> {
 8657        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>());
 8658        let inlay_highlights = self
 8659            .inlay_background_highlights
 8660            .remove(&Some(TypeId::of::<T>()));
 8661        if text_highlights.is_some() || inlay_highlights.is_some() {
 8662            cx.notify();
 8663        }
 8664        text_highlights
 8665    }
 8666
 8667    #[cfg(feature = "test-support")]
 8668    pub fn all_text_background_highlights(
 8669        &mut self,
 8670        cx: &mut ViewContext<Self>,
 8671    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
 8672        let snapshot = self.snapshot(cx);
 8673        let buffer = &snapshot.buffer_snapshot;
 8674        let start = buffer.anchor_before(0);
 8675        let end = buffer.anchor_after(buffer.len());
 8676        let theme = cx.theme().colors();
 8677        self.background_highlights_in_range(start..end, &snapshot, theme)
 8678    }
 8679
 8680    fn document_highlights_for_position<'a>(
 8681        &'a self,
 8682        position: Anchor,
 8683        buffer: &'a MultiBufferSnapshot,
 8684    ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
 8685        let read_highlights = self
 8686            .background_highlights
 8687            .get(&TypeId::of::<DocumentHighlightRead>())
 8688            .map(|h| &h.1);
 8689        let write_highlights = self
 8690            .background_highlights
 8691            .get(&TypeId::of::<DocumentHighlightWrite>())
 8692            .map(|h| &h.1);
 8693        let left_position = position.bias_left(buffer);
 8694        let right_position = position.bias_right(buffer);
 8695        read_highlights
 8696            .into_iter()
 8697            .chain(write_highlights)
 8698            .flat_map(move |ranges| {
 8699                let start_ix = match ranges.binary_search_by(|probe| {
 8700                    let cmp = probe.end.cmp(&left_position, buffer);
 8701                    if cmp.is_ge() {
 8702                        Ordering::Greater
 8703                    } else {
 8704                        Ordering::Less
 8705                    }
 8706                }) {
 8707                    Ok(i) | Err(i) => i,
 8708                };
 8709
 8710                let right_position = right_position.clone();
 8711                ranges[start_ix..]
 8712                    .iter()
 8713                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
 8714            })
 8715    }
 8716
 8717    pub fn has_background_highlights<T: 'static>(&self) -> bool {
 8718        self.background_highlights
 8719            .get(&TypeId::of::<T>())
 8720            .map_or(false, |(_, highlights)| !highlights.is_empty())
 8721    }
 8722
 8723    pub fn background_highlights_in_range(
 8724        &self,
 8725        search_range: Range<Anchor>,
 8726        display_snapshot: &DisplaySnapshot,
 8727        theme: &ThemeColors,
 8728    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
 8729        let mut results = Vec::new();
 8730        for (color_fetcher, ranges) in self.background_highlights.values() {
 8731            let color = color_fetcher(theme);
 8732            let start_ix = match ranges.binary_search_by(|probe| {
 8733                let cmp = probe
 8734                    .end
 8735                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
 8736                if cmp.is_gt() {
 8737                    Ordering::Greater
 8738                } else {
 8739                    Ordering::Less
 8740                }
 8741            }) {
 8742                Ok(i) | Err(i) => i,
 8743            };
 8744            for range in &ranges[start_ix..] {
 8745                if range
 8746                    .start
 8747                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
 8748                    .is_ge()
 8749                {
 8750                    break;
 8751                }
 8752
 8753                let start = range.start.to_display_point(&display_snapshot);
 8754                let end = range.end.to_display_point(&display_snapshot);
 8755                results.push((start..end, color))
 8756            }
 8757        }
 8758        results
 8759    }
 8760
 8761    pub fn background_highlight_row_ranges<T: 'static>(
 8762        &self,
 8763        search_range: Range<Anchor>,
 8764        display_snapshot: &DisplaySnapshot,
 8765        count: usize,
 8766    ) -> Vec<RangeInclusive<DisplayPoint>> {
 8767        let mut results = Vec::new();
 8768        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
 8769            return vec![];
 8770        };
 8771
 8772        let start_ix = match ranges.binary_search_by(|probe| {
 8773            let cmp = probe
 8774                .end
 8775                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
 8776            if cmp.is_gt() {
 8777                Ordering::Greater
 8778            } else {
 8779                Ordering::Less
 8780            }
 8781        }) {
 8782            Ok(i) | Err(i) => i,
 8783        };
 8784        let mut push_region = |start: Option<Point>, end: Option<Point>| {
 8785            if let (Some(start_display), Some(end_display)) = (start, end) {
 8786                results.push(
 8787                    start_display.to_display_point(display_snapshot)
 8788                        ..=end_display.to_display_point(display_snapshot),
 8789                );
 8790            }
 8791        };
 8792        let mut start_row: Option<Point> = None;
 8793        let mut end_row: Option<Point> = None;
 8794        if ranges.len() > count {
 8795            return Vec::new();
 8796        }
 8797        for range in &ranges[start_ix..] {
 8798            if range
 8799                .start
 8800                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
 8801                .is_ge()
 8802            {
 8803                break;
 8804            }
 8805            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
 8806            if let Some(current_row) = &end_row {
 8807                if end.row == current_row.row {
 8808                    continue;
 8809                }
 8810            }
 8811            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
 8812            if start_row.is_none() {
 8813                assert_eq!(end_row, None);
 8814                start_row = Some(start);
 8815                end_row = Some(end);
 8816                continue;
 8817            }
 8818            if let Some(current_end) = end_row.as_mut() {
 8819                if start.row > current_end.row + 1 {
 8820                    push_region(start_row, end_row);
 8821                    start_row = Some(start);
 8822                    end_row = Some(end);
 8823                } else {
 8824                    // Merge two hunks.
 8825                    *current_end = end;
 8826                }
 8827            } else {
 8828                unreachable!();
 8829            }
 8830        }
 8831        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
 8832        push_region(start_row, end_row);
 8833        results
 8834    }
 8835
 8836    /// Get the text ranges corresponding to the redaction query
 8837    pub fn redacted_ranges(
 8838        &self,
 8839        search_range: Range<Anchor>,
 8840        display_snapshot: &DisplaySnapshot,
 8841        cx: &mut ViewContext<Self>,
 8842    ) -> Vec<Range<DisplayPoint>> {
 8843        display_snapshot
 8844            .buffer_snapshot
 8845            .redacted_ranges(search_range, |file| {
 8846                if let Some(file) = file {
 8847                    file.is_private()
 8848                        && EditorSettings::get(Some((file.worktree_id(), file.path())), cx)
 8849                            .redact_private_values
 8850                } else {
 8851                    false
 8852                }
 8853            })
 8854            .map(|range| {
 8855                range.start.to_display_point(display_snapshot)
 8856                    ..range.end.to_display_point(display_snapshot)
 8857            })
 8858            .collect()
 8859    }
 8860
 8861    pub fn highlight_text<T: 'static>(
 8862        &mut self,
 8863        ranges: Vec<Range<Anchor>>,
 8864        style: HighlightStyle,
 8865        cx: &mut ViewContext<Self>,
 8866    ) {
 8867        self.display_map.update(cx, |map, _| {
 8868            map.highlight_text(TypeId::of::<T>(), ranges, style)
 8869        });
 8870        cx.notify();
 8871    }
 8872
 8873    pub(crate) fn highlight_inlays<T: 'static>(
 8874        &mut self,
 8875        highlights: Vec<InlayHighlight>,
 8876        style: HighlightStyle,
 8877        cx: &mut ViewContext<Self>,
 8878    ) {
 8879        self.display_map.update(cx, |map, _| {
 8880            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
 8881        });
 8882        cx.notify();
 8883    }
 8884
 8885    pub fn text_highlights<'a, T: 'static>(
 8886        &'a self,
 8887        cx: &'a AppContext,
 8888    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
 8889        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
 8890    }
 8891
 8892    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut ViewContext<Self>) {
 8893        let cleared = self
 8894            .display_map
 8895            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
 8896        if cleared {
 8897            cx.notify();
 8898        }
 8899    }
 8900
 8901    pub fn show_local_cursors(&self, cx: &WindowContext) -> bool {
 8902        (self.read_only(cx) || self.blink_manager.read(cx).visible())
 8903            && self.focus_handle.is_focused(cx)
 8904    }
 8905
 8906    fn on_buffer_changed(&mut self, _: Model<MultiBuffer>, cx: &mut ViewContext<Self>) {
 8907        cx.notify();
 8908    }
 8909
 8910    fn on_buffer_event(
 8911        &mut self,
 8912        multibuffer: Model<MultiBuffer>,
 8913        event: &multi_buffer::Event,
 8914        cx: &mut ViewContext<Self>,
 8915    ) {
 8916        match event {
 8917            multi_buffer::Event::Edited {
 8918                singleton_buffer_edited,
 8919            } => {
 8920                self.refresh_active_diagnostics(cx);
 8921                self.refresh_code_actions(cx);
 8922                if self.has_active_copilot_suggestion(cx) {
 8923                    self.update_visible_copilot_suggestion(cx);
 8924                }
 8925                cx.emit(EditorEvent::BufferEdited);
 8926                cx.emit(SearchEvent::MatchesInvalidated);
 8927
 8928                if *singleton_buffer_edited {
 8929                    if let Some(project) = &self.project {
 8930                        let project = project.read(cx);
 8931                        let languages_affected = multibuffer
 8932                            .read(cx)
 8933                            .all_buffers()
 8934                            .into_iter()
 8935                            .filter_map(|buffer| {
 8936                                let buffer = buffer.read(cx);
 8937                                let language = buffer.language()?;
 8938                                if project.is_local()
 8939                                    && project.language_servers_for_buffer(buffer, cx).count() == 0
 8940                                {
 8941                                    None
 8942                                } else {
 8943                                    Some(language)
 8944                                }
 8945                            })
 8946                            .cloned()
 8947                            .collect::<HashSet<_>>();
 8948                        if !languages_affected.is_empty() {
 8949                            self.refresh_inlay_hints(
 8950                                InlayHintRefreshReason::BufferEdited(languages_affected),
 8951                                cx,
 8952                            );
 8953                        }
 8954                    }
 8955                }
 8956
 8957                let Some(project) = &self.project else { return };
 8958                let telemetry = project.read(cx).client().telemetry().clone();
 8959                telemetry.log_edit_event("editor");
 8960            }
 8961            multi_buffer::Event::ExcerptsAdded {
 8962                buffer,
 8963                predecessor,
 8964                excerpts,
 8965            } => {
 8966                cx.emit(EditorEvent::ExcerptsAdded {
 8967                    buffer: buffer.clone(),
 8968                    predecessor: *predecessor,
 8969                    excerpts: excerpts.clone(),
 8970                });
 8971                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 8972            }
 8973            multi_buffer::Event::ExcerptsRemoved { ids } => {
 8974                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
 8975                cx.emit(EditorEvent::ExcerptsRemoved { ids: ids.clone() })
 8976            }
 8977            multi_buffer::Event::Reparsed => cx.emit(EditorEvent::Reparsed),
 8978            multi_buffer::Event::LanguageChanged => {
 8979                cx.emit(EditorEvent::Reparsed);
 8980                cx.notify();
 8981            }
 8982            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
 8983            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
 8984            multi_buffer::Event::FileHandleChanged | multi_buffer::Event::Reloaded => {
 8985                cx.emit(EditorEvent::TitleChanged)
 8986            }
 8987            multi_buffer::Event::DiffBaseChanged => cx.emit(EditorEvent::DiffBaseChanged),
 8988            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
 8989            multi_buffer::Event::DiagnosticsUpdated => {
 8990                self.refresh_active_diagnostics(cx);
 8991            }
 8992            _ => {}
 8993        };
 8994    }
 8995
 8996    fn on_display_map_changed(&mut self, _: Model<DisplayMap>, cx: &mut ViewContext<Self>) {
 8997        cx.notify();
 8998    }
 8999
 9000    fn settings_changed(&mut self, cx: &mut ViewContext<Self>) {
 9001        self.refresh_copilot_suggestions(true, cx);
 9002        self.refresh_inlay_hints(
 9003            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
 9004                self.selections.newest_anchor().head(),
 9005                &self.buffer.read(cx).snapshot(cx),
 9006                cx,
 9007            )),
 9008            cx,
 9009        );
 9010        let editor_settings = EditorSettings::get_global(cx);
 9011        self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
 9012        self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
 9013        cx.notify();
 9014    }
 9015
 9016    pub fn set_searchable(&mut self, searchable: bool) {
 9017        self.searchable = searchable;
 9018    }
 9019
 9020    pub fn searchable(&self) -> bool {
 9021        self.searchable
 9022    }
 9023
 9024    fn open_excerpts(&mut self, _: &OpenExcerpts, cx: &mut ViewContext<Self>) {
 9025        let buffer = self.buffer.read(cx);
 9026        if buffer.is_singleton() {
 9027            cx.propagate();
 9028            return;
 9029        }
 9030
 9031        let Some(workspace) = self.workspace() else {
 9032            cx.propagate();
 9033            return;
 9034        };
 9035
 9036        let mut new_selections_by_buffer = HashMap::default();
 9037        for selection in self.selections.all::<usize>(cx) {
 9038            for (buffer, mut range, _) in
 9039                buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
 9040            {
 9041                if selection.reversed {
 9042                    mem::swap(&mut range.start, &mut range.end);
 9043                }
 9044                new_selections_by_buffer
 9045                    .entry(buffer)
 9046                    .or_insert(Vec::new())
 9047                    .push(range)
 9048            }
 9049        }
 9050
 9051        self.push_to_nav_history(self.selections.newest_anchor().head(), None, cx);
 9052
 9053        // We defer the pane interaction because we ourselves are a workspace item
 9054        // and activating a new item causes the pane to call a method on us reentrantly,
 9055        // which panics if we're on the stack.
 9056        cx.window_context().defer(move |cx| {
 9057            workspace.update(cx, |workspace, cx| {
 9058                let pane = workspace.active_pane().clone();
 9059                pane.update(cx, |pane, _| pane.disable_history());
 9060
 9061                for (buffer, ranges) in new_selections_by_buffer.into_iter() {
 9062                    let editor = workspace.open_project_item::<Self>(buffer, cx);
 9063                    editor.update(cx, |editor, cx| {
 9064                        editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
 9065                            s.select_ranges(ranges);
 9066                        });
 9067                    });
 9068                }
 9069
 9070                pane.update(cx, |pane, _| pane.enable_history());
 9071            })
 9072        });
 9073    }
 9074
 9075    fn jump(
 9076        &mut self,
 9077        path: ProjectPath,
 9078        position: Point,
 9079        anchor: language::Anchor,
 9080        cx: &mut ViewContext<Self>,
 9081    ) {
 9082        let workspace = self.workspace();
 9083        cx.spawn(|_, mut cx| async move {
 9084            let workspace = workspace.ok_or_else(|| anyhow!("cannot jump without workspace"))?;
 9085            let editor = workspace.update(&mut cx, |workspace, cx| {
 9086                workspace.open_path(path, None, true, cx)
 9087            })?;
 9088            let editor = editor
 9089                .await?
 9090                .downcast::<Editor>()
 9091                .ok_or_else(|| anyhow!("opened item was not an editor"))?
 9092                .downgrade();
 9093            editor.update(&mut cx, |editor, cx| {
 9094                let buffer = editor
 9095                    .buffer()
 9096                    .read(cx)
 9097                    .as_singleton()
 9098                    .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?;
 9099                let buffer = buffer.read(cx);
 9100                let cursor = if buffer.can_resolve(&anchor) {
 9101                    language::ToPoint::to_point(&anchor, buffer)
 9102                } else {
 9103                    buffer.clip_point(position, Bias::Left)
 9104                };
 9105
 9106                let nav_history = editor.nav_history.take();
 9107                editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
 9108                    s.select_ranges([cursor..cursor]);
 9109                });
 9110                editor.nav_history = nav_history;
 9111
 9112                anyhow::Ok(())
 9113            })??;
 9114
 9115            anyhow::Ok(())
 9116        })
 9117        .detach_and_log_err(cx);
 9118    }
 9119
 9120    fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
 9121        let snapshot = self.buffer.read(cx).read(cx);
 9122        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
 9123        Some(
 9124            ranges
 9125                .iter()
 9126                .map(move |range| {
 9127                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
 9128                })
 9129                .collect(),
 9130        )
 9131    }
 9132
 9133    fn selection_replacement_ranges(
 9134        &self,
 9135        range: Range<OffsetUtf16>,
 9136        cx: &AppContext,
 9137    ) -> Vec<Range<OffsetUtf16>> {
 9138        let selections = self.selections.all::<OffsetUtf16>(cx);
 9139        let newest_selection = selections
 9140            .iter()
 9141            .max_by_key(|selection| selection.id)
 9142            .unwrap();
 9143        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
 9144        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
 9145        let snapshot = self.buffer.read(cx).read(cx);
 9146        selections
 9147            .into_iter()
 9148            .map(|mut selection| {
 9149                selection.start.0 =
 9150                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
 9151                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
 9152                snapshot.clip_offset_utf16(selection.start, Bias::Left)
 9153                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
 9154            })
 9155            .collect()
 9156    }
 9157
 9158    fn report_copilot_event(
 9159        &self,
 9160        suggestion_id: Option<String>,
 9161        suggestion_accepted: bool,
 9162        cx: &AppContext,
 9163    ) {
 9164        let Some(project) = &self.project else { return };
 9165
 9166        // If None, we are either getting suggestions in a new, unsaved file, or in a file without an extension
 9167        let file_extension = self
 9168            .buffer
 9169            .read(cx)
 9170            .as_singleton()
 9171            .and_then(|b| b.read(cx).file())
 9172            .and_then(|file| Path::new(file.file_name(cx)).extension())
 9173            .and_then(|e| e.to_str())
 9174            .map(|a| a.to_string());
 9175
 9176        let telemetry = project.read(cx).client().telemetry().clone();
 9177
 9178        telemetry.report_copilot_event(suggestion_id, suggestion_accepted, file_extension)
 9179    }
 9180
 9181    #[cfg(any(test, feature = "test-support"))]
 9182    fn report_editor_event(
 9183        &self,
 9184        _operation: &'static str,
 9185        _file_extension: Option<String>,
 9186        _cx: &AppContext,
 9187    ) {
 9188    }
 9189
 9190    #[cfg(not(any(test, feature = "test-support")))]
 9191    fn report_editor_event(
 9192        &self,
 9193        operation: &'static str,
 9194        file_extension: Option<String>,
 9195        cx: &AppContext,
 9196    ) {
 9197        let Some(project) = &self.project else { return };
 9198
 9199        // If None, we are in a file without an extension
 9200        let file = self
 9201            .buffer
 9202            .read(cx)
 9203            .as_singleton()
 9204            .and_then(|b| b.read(cx).file());
 9205        let file_extension = file_extension.or(file
 9206            .as_ref()
 9207            .and_then(|file| Path::new(file.file_name(cx)).extension())
 9208            .and_then(|e| e.to_str())
 9209            .map(|a| a.to_string()));
 9210
 9211        let vim_mode = cx
 9212            .global::<SettingsStore>()
 9213            .raw_user_settings()
 9214            .get("vim_mode")
 9215            == Some(&serde_json::Value::Bool(true));
 9216        let copilot_enabled = all_language_settings(file, cx).copilot_enabled(None, None);
 9217        let copilot_enabled_for_language = self
 9218            .buffer
 9219            .read(cx)
 9220            .settings_at(0, cx)
 9221            .show_copilot_suggestions;
 9222
 9223        let telemetry = project.read(cx).client().telemetry().clone();
 9224        telemetry.report_editor_event(
 9225            file_extension,
 9226            vim_mode,
 9227            operation,
 9228            copilot_enabled,
 9229            copilot_enabled_for_language,
 9230        )
 9231    }
 9232
 9233    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
 9234    /// with each line being an array of {text, highlight} objects.
 9235    fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext<Self>) {
 9236        let Some(buffer) = self.buffer.read(cx).as_singleton() else {
 9237            return;
 9238        };
 9239
 9240        #[derive(Serialize)]
 9241        struct Chunk<'a> {
 9242            text: String,
 9243            highlight: Option<&'a str>,
 9244        }
 9245
 9246        let snapshot = buffer.read(cx).snapshot();
 9247        let range = self
 9248            .selected_text_range(cx)
 9249            .and_then(|selected_range| {
 9250                if selected_range.is_empty() {
 9251                    None
 9252                } else {
 9253                    Some(selected_range)
 9254                }
 9255            })
 9256            .unwrap_or_else(|| 0..snapshot.len());
 9257
 9258        let chunks = snapshot.chunks(range, true);
 9259        let mut lines = Vec::new();
 9260        let mut line: VecDeque<Chunk> = VecDeque::new();
 9261
 9262        let Some(style) = self.style.as_ref() else {
 9263            return;
 9264        };
 9265
 9266        for chunk in chunks {
 9267            let highlight = chunk
 9268                .syntax_highlight_id
 9269                .and_then(|id| id.name(&style.syntax));
 9270            let mut chunk_lines = chunk.text.split("\n").peekable();
 9271            while let Some(text) = chunk_lines.next() {
 9272                let mut merged_with_last_token = false;
 9273                if let Some(last_token) = line.back_mut() {
 9274                    if last_token.highlight == highlight {
 9275                        last_token.text.push_str(text);
 9276                        merged_with_last_token = true;
 9277                    }
 9278                }
 9279
 9280                if !merged_with_last_token {
 9281                    line.push_back(Chunk {
 9282                        text: text.into(),
 9283                        highlight,
 9284                    });
 9285                }
 9286
 9287                if chunk_lines.peek().is_some() {
 9288                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
 9289                        line.pop_front();
 9290                    }
 9291                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
 9292                        line.pop_back();
 9293                    }
 9294
 9295                    lines.push(mem::take(&mut line));
 9296                }
 9297            }
 9298        }
 9299
 9300        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
 9301            return;
 9302        };
 9303        cx.write_to_clipboard(ClipboardItem::new(lines));
 9304    }
 9305
 9306    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
 9307        &self.inlay_hint_cache
 9308    }
 9309
 9310    pub fn replay_insert_event(
 9311        &mut self,
 9312        text: &str,
 9313        relative_utf16_range: Option<Range<isize>>,
 9314        cx: &mut ViewContext<Self>,
 9315    ) {
 9316        if !self.input_enabled {
 9317            cx.emit(EditorEvent::InputIgnored { text: text.into() });
 9318            return;
 9319        }
 9320        if let Some(relative_utf16_range) = relative_utf16_range {
 9321            let selections = self.selections.all::<OffsetUtf16>(cx);
 9322            self.change_selections(None, cx, |s| {
 9323                let new_ranges = selections.into_iter().map(|range| {
 9324                    let start = OffsetUtf16(
 9325                        range
 9326                            .head()
 9327                            .0
 9328                            .saturating_add_signed(relative_utf16_range.start),
 9329                    );
 9330                    let end = OffsetUtf16(
 9331                        range
 9332                            .head()
 9333                            .0
 9334                            .saturating_add_signed(relative_utf16_range.end),
 9335                    );
 9336                    start..end
 9337                });
 9338                s.select_ranges(new_ranges);
 9339            });
 9340        }
 9341
 9342        self.handle_input(text, cx);
 9343    }
 9344
 9345    pub fn supports_inlay_hints(&self, cx: &AppContext) -> bool {
 9346        let Some(project) = self.project.as_ref() else {
 9347            return false;
 9348        };
 9349        let project = project.read(cx);
 9350
 9351        let mut supports = false;
 9352        self.buffer().read(cx).for_each_buffer(|buffer| {
 9353            if !supports {
 9354                supports = project
 9355                    .language_servers_for_buffer(buffer.read(cx), cx)
 9356                    .any(
 9357                        |(_, server)| match server.capabilities().inlay_hint_provider {
 9358                            Some(lsp::OneOf::Left(enabled)) => enabled,
 9359                            Some(lsp::OneOf::Right(_)) => true,
 9360                            None => false,
 9361                        },
 9362                    )
 9363            }
 9364        });
 9365        supports
 9366    }
 9367
 9368    pub fn focus(&self, cx: &mut WindowContext) {
 9369        cx.focus(&self.focus_handle)
 9370    }
 9371
 9372    pub fn is_focused(&self, cx: &WindowContext) -> bool {
 9373        self.focus_handle.is_focused(cx)
 9374    }
 9375
 9376    fn handle_focus(&mut self, cx: &mut ViewContext<Self>) {
 9377        cx.emit(EditorEvent::Focused);
 9378
 9379        if let Some(rename) = self.pending_rename.as_ref() {
 9380            let rename_editor_focus_handle = rename.editor.read(cx).focus_handle.clone();
 9381            cx.focus(&rename_editor_focus_handle);
 9382        } else {
 9383            self.blink_manager.update(cx, BlinkManager::enable);
 9384            self.show_cursor_names(cx);
 9385            self.buffer.update(cx, |buffer, cx| {
 9386                buffer.finalize_last_transaction(cx);
 9387                if self.leader_peer_id.is_none() {
 9388                    buffer.set_active_selections(
 9389                        &self.selections.disjoint_anchors(),
 9390                        self.selections.line_mode,
 9391                        self.cursor_shape,
 9392                        cx,
 9393                    );
 9394                }
 9395            });
 9396        }
 9397    }
 9398
 9399    pub fn handle_blur(&mut self, cx: &mut ViewContext<Self>) {
 9400        self.blink_manager.update(cx, BlinkManager::disable);
 9401        self.buffer
 9402            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
 9403        self.hide_context_menu(cx);
 9404        hide_hover(self, cx);
 9405        cx.emit(EditorEvent::Blurred);
 9406        cx.notify();
 9407    }
 9408
 9409    pub fn register_action<A: Action>(
 9410        &mut self,
 9411        listener: impl Fn(&A, &mut WindowContext) + 'static,
 9412    ) -> &mut Self {
 9413        let listener = Arc::new(listener);
 9414
 9415        self.editor_actions.push(Box::new(move |cx| {
 9416            let _view = cx.view().clone();
 9417            let cx = cx.window_context();
 9418            let listener = listener.clone();
 9419            cx.on_action(TypeId::of::<A>(), move |action, phase, cx| {
 9420                let action = action.downcast_ref().unwrap();
 9421                if phase == DispatchPhase::Bubble {
 9422                    listener(action, cx)
 9423                }
 9424            })
 9425        }));
 9426        self
 9427    }
 9428}
 9429
 9430pub trait CollaborationHub {
 9431    fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator>;
 9432    fn user_participant_indices<'a>(
 9433        &self,
 9434        cx: &'a AppContext,
 9435    ) -> &'a HashMap<u64, ParticipantIndex>;
 9436    fn user_names(&self, cx: &AppContext) -> HashMap<u64, SharedString>;
 9437}
 9438
 9439impl CollaborationHub for Model<Project> {
 9440    fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator> {
 9441        self.read(cx).collaborators()
 9442    }
 9443
 9444    fn user_participant_indices<'a>(
 9445        &self,
 9446        cx: &'a AppContext,
 9447    ) -> &'a HashMap<u64, ParticipantIndex> {
 9448        self.read(cx).user_store().read(cx).participant_indices()
 9449    }
 9450
 9451    fn user_names(&self, cx: &AppContext) -> HashMap<u64, SharedString> {
 9452        let this = self.read(cx);
 9453        let user_ids = this.collaborators().values().map(|c| c.user_id);
 9454        this.user_store().read_with(cx, |user_store, cx| {
 9455            user_store.participant_names(user_ids, cx)
 9456        })
 9457    }
 9458}
 9459
 9460pub trait CompletionProvider {
 9461    fn completions(
 9462        &self,
 9463        buffer: &Model<Buffer>,
 9464        buffer_position: text::Anchor,
 9465        cx: &mut ViewContext<Editor>,
 9466    ) -> Task<Result<Vec<Completion>>>;
 9467
 9468    fn resolve_completions(
 9469        &self,
 9470        completion_indices: Vec<usize>,
 9471        completions: Arc<RwLock<Box<[Completion]>>>,
 9472        cx: &mut ViewContext<Editor>,
 9473    ) -> Task<Result<bool>>;
 9474
 9475    fn apply_additional_edits_for_completion(
 9476        &self,
 9477        buffer: Model<Buffer>,
 9478        completion: Completion,
 9479        push_to_history: bool,
 9480        cx: &mut ViewContext<Editor>,
 9481    ) -> Task<Result<Option<language::Transaction>>>;
 9482}
 9483
 9484impl CompletionProvider for Model<Project> {
 9485    fn completions(
 9486        &self,
 9487        buffer: &Model<Buffer>,
 9488        buffer_position: text::Anchor,
 9489        cx: &mut ViewContext<Editor>,
 9490    ) -> Task<Result<Vec<Completion>>> {
 9491        self.update(cx, |project, cx| {
 9492            project.completions(&buffer, buffer_position, cx)
 9493        })
 9494    }
 9495
 9496    fn resolve_completions(
 9497        &self,
 9498        completion_indices: Vec<usize>,
 9499        completions: Arc<RwLock<Box<[Completion]>>>,
 9500        cx: &mut ViewContext<Editor>,
 9501    ) -> Task<Result<bool>> {
 9502        self.update(cx, |project, cx| {
 9503            project.resolve_completions(completion_indices, completions, cx)
 9504        })
 9505    }
 9506
 9507    fn apply_additional_edits_for_completion(
 9508        &self,
 9509        buffer: Model<Buffer>,
 9510        completion: Completion,
 9511        push_to_history: bool,
 9512        cx: &mut ViewContext<Editor>,
 9513    ) -> Task<Result<Option<language::Transaction>>> {
 9514        self.update(cx, |project, cx| {
 9515            project.apply_additional_edits_for_completion(buffer, completion, push_to_history, cx)
 9516        })
 9517    }
 9518}
 9519
 9520fn inlay_hint_settings(
 9521    location: Anchor,
 9522    snapshot: &MultiBufferSnapshot,
 9523    cx: &mut ViewContext<'_, Editor>,
 9524) -> InlayHintSettings {
 9525    let file = snapshot.file_at(location);
 9526    let language = snapshot.language_at(location);
 9527    let settings = all_language_settings(file, cx);
 9528    settings
 9529        .language(language.map(|l| l.name()).as_deref())
 9530        .inlay_hints
 9531}
 9532
 9533fn consume_contiguous_rows(
 9534    contiguous_row_selections: &mut Vec<Selection<Point>>,
 9535    selection: &Selection<Point>,
 9536    display_map: &DisplaySnapshot,
 9537    selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
 9538) -> (u32, u32) {
 9539    contiguous_row_selections.push(selection.clone());
 9540    let start_row = selection.start.row;
 9541    let mut end_row = ending_row(selection, display_map);
 9542
 9543    while let Some(next_selection) = selections.peek() {
 9544        if next_selection.start.row <= end_row {
 9545            end_row = ending_row(next_selection, display_map);
 9546            contiguous_row_selections.push(selections.next().unwrap().clone());
 9547        } else {
 9548            break;
 9549        }
 9550    }
 9551    (start_row, end_row)
 9552}
 9553
 9554fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
 9555    if next_selection.end.column > 0 || next_selection.is_empty() {
 9556        display_map.next_line_boundary(next_selection.end).0.row + 1
 9557    } else {
 9558        next_selection.end.row
 9559    }
 9560}
 9561
 9562impl EditorSnapshot {
 9563    pub fn remote_selections_in_range<'a>(
 9564        &'a self,
 9565        range: &'a Range<Anchor>,
 9566        collaboration_hub: &dyn CollaborationHub,
 9567        cx: &'a AppContext,
 9568    ) -> impl 'a + Iterator<Item = RemoteSelection> {
 9569        let participant_names = collaboration_hub.user_names(cx);
 9570        let participant_indices = collaboration_hub.user_participant_indices(cx);
 9571        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
 9572        let collaborators_by_replica_id = collaborators_by_peer_id
 9573            .iter()
 9574            .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
 9575            .collect::<HashMap<_, _>>();
 9576        self.buffer_snapshot
 9577            .remote_selections_in_range(range)
 9578            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
 9579                let collaborator = collaborators_by_replica_id.get(&replica_id)?;
 9580                let participant_index = participant_indices.get(&collaborator.user_id).copied();
 9581                let user_name = participant_names.get(&collaborator.user_id).cloned();
 9582                Some(RemoteSelection {
 9583                    replica_id,
 9584                    selection,
 9585                    cursor_shape,
 9586                    line_mode,
 9587                    participant_index,
 9588                    peer_id: collaborator.peer_id,
 9589                    user_name,
 9590                })
 9591            })
 9592    }
 9593
 9594    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
 9595        self.display_snapshot.buffer_snapshot.language_at(position)
 9596    }
 9597
 9598    pub fn is_focused(&self) -> bool {
 9599        self.is_focused
 9600    }
 9601
 9602    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
 9603        self.placeholder_text.as_ref()
 9604    }
 9605
 9606    pub fn scroll_position(&self) -> gpui::Point<f32> {
 9607        self.scroll_anchor.scroll_position(&self.display_snapshot)
 9608    }
 9609
 9610    pub fn gutter_dimensions(
 9611        &self,
 9612        font_id: FontId,
 9613        font_size: Pixels,
 9614        em_width: Pixels,
 9615        max_line_number_width: Pixels,
 9616        cx: &AppContext,
 9617    ) -> GutterDimensions {
 9618        if self.show_gutter {
 9619            let descent = cx.text_system().descent(font_id, font_size);
 9620            let gutter_padding_factor = 4.0;
 9621            let gutter_padding = (em_width * gutter_padding_factor).round();
 9622            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
 9623            let min_width_for_number_on_gutter = em_width * 4.0;
 9624            let gutter_width =
 9625                max_line_number_width.max(min_width_for_number_on_gutter) + gutter_padding * 2.0;
 9626            let gutter_margin = -descent;
 9627
 9628            GutterDimensions {
 9629                padding: gutter_padding,
 9630                width: gutter_width,
 9631                margin: gutter_margin,
 9632            }
 9633        } else {
 9634            GutterDimensions::default()
 9635        }
 9636    }
 9637}
 9638
 9639impl Deref for EditorSnapshot {
 9640    type Target = DisplaySnapshot;
 9641
 9642    fn deref(&self) -> &Self::Target {
 9643        &self.display_snapshot
 9644    }
 9645}
 9646
 9647#[derive(Clone, Debug, PartialEq, Eq)]
 9648pub enum EditorEvent {
 9649    InputIgnored {
 9650        text: Arc<str>,
 9651    },
 9652    InputHandled {
 9653        utf16_range_to_replace: Option<Range<isize>>,
 9654        text: Arc<str>,
 9655    },
 9656    ExcerptsAdded {
 9657        buffer: Model<Buffer>,
 9658        predecessor: ExcerptId,
 9659        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
 9660    },
 9661    ExcerptsRemoved {
 9662        ids: Vec<ExcerptId>,
 9663    },
 9664    BufferEdited,
 9665    Edited,
 9666    Reparsed,
 9667    Focused,
 9668    Blurred,
 9669    DirtyChanged,
 9670    Saved,
 9671    TitleChanged,
 9672    DiffBaseChanged,
 9673    SelectionsChanged {
 9674        local: bool,
 9675    },
 9676    ScrollPositionChanged {
 9677        local: bool,
 9678        autoscroll: bool,
 9679    },
 9680    Closed,
 9681}
 9682
 9683impl EventEmitter<EditorEvent> for Editor {}
 9684
 9685impl FocusableView for Editor {
 9686    fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
 9687        self.focus_handle.clone()
 9688    }
 9689}
 9690
 9691impl Render for Editor {
 9692    fn render<'a>(&mut self, cx: &mut ViewContext<'a, Self>) -> impl IntoElement {
 9693        let settings = ThemeSettings::get_global(cx);
 9694        let text_style = match self.mode {
 9695            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
 9696                color: cx.theme().colors().editor_foreground,
 9697                font_family: settings.ui_font.family.clone(),
 9698                font_features: settings.ui_font.features,
 9699                font_size: rems(0.875).into(),
 9700                font_weight: FontWeight::NORMAL,
 9701                font_style: FontStyle::Normal,
 9702                line_height: relative(settings.buffer_line_height.value()),
 9703                background_color: None,
 9704                underline: None,
 9705                strikethrough: None,
 9706                white_space: WhiteSpace::Normal,
 9707            },
 9708
 9709            EditorMode::Full => TextStyle {
 9710                color: cx.theme().colors().editor_foreground,
 9711                font_family: settings.buffer_font.family.clone(),
 9712                font_features: settings.buffer_font.features,
 9713                font_size: settings.buffer_font_size(cx).into(),
 9714                font_weight: FontWeight::NORMAL,
 9715                font_style: FontStyle::Normal,
 9716                line_height: relative(settings.buffer_line_height.value()),
 9717                background_color: None,
 9718                underline: None,
 9719                strikethrough: None,
 9720                white_space: WhiteSpace::Normal,
 9721            },
 9722        };
 9723
 9724        let background = match self.mode {
 9725            EditorMode::SingleLine => cx.theme().system().transparent,
 9726            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
 9727            EditorMode::Full => cx.theme().colors().editor_background,
 9728        };
 9729
 9730        EditorElement::new(
 9731            cx.view(),
 9732            EditorStyle {
 9733                background,
 9734                local_player: cx.theme().players().local(),
 9735                text: text_style,
 9736                scrollbar_width: px(12.),
 9737                syntax: cx.theme().syntax().clone(),
 9738                status: cx.theme().status().clone(),
 9739                inlays_style: HighlightStyle {
 9740                    color: Some(cx.theme().status().hint),
 9741                    font_weight: Some(FontWeight::BOLD),
 9742                    ..HighlightStyle::default()
 9743                },
 9744                suggestions_style: HighlightStyle {
 9745                    color: Some(cx.theme().status().predictive),
 9746                    ..HighlightStyle::default()
 9747                },
 9748            },
 9749        )
 9750    }
 9751}
 9752
 9753impl ViewInputHandler for Editor {
 9754    fn text_for_range(
 9755        &mut self,
 9756        range_utf16: Range<usize>,
 9757        cx: &mut ViewContext<Self>,
 9758    ) -> Option<String> {
 9759        Some(
 9760            self.buffer
 9761                .read(cx)
 9762                .read(cx)
 9763                .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
 9764                .collect(),
 9765        )
 9766    }
 9767
 9768    fn selected_text_range(&mut self, cx: &mut ViewContext<Self>) -> Option<Range<usize>> {
 9769        // Prevent the IME menu from appearing when holding down an alphabetic key
 9770        // while input is disabled.
 9771        if !self.input_enabled {
 9772            return None;
 9773        }
 9774
 9775        let range = self.selections.newest::<OffsetUtf16>(cx).range();
 9776        Some(range.start.0..range.end.0)
 9777    }
 9778
 9779    fn marked_text_range(&self, cx: &mut ViewContext<Self>) -> Option<Range<usize>> {
 9780        let snapshot = self.buffer.read(cx).read(cx);
 9781        let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
 9782        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
 9783    }
 9784
 9785    fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
 9786        self.clear_highlights::<InputComposition>(cx);
 9787        self.ime_transaction.take();
 9788    }
 9789
 9790    fn replace_text_in_range(
 9791        &mut self,
 9792        range_utf16: Option<Range<usize>>,
 9793        text: &str,
 9794        cx: &mut ViewContext<Self>,
 9795    ) {
 9796        if !self.input_enabled {
 9797            cx.emit(EditorEvent::InputIgnored { text: text.into() });
 9798            return;
 9799        }
 9800
 9801        self.transact(cx, |this, cx| {
 9802            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
 9803                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
 9804                Some(this.selection_replacement_ranges(range_utf16, cx))
 9805            } else {
 9806                this.marked_text_ranges(cx)
 9807            };
 9808
 9809            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
 9810                let newest_selection_id = this.selections.newest_anchor().id;
 9811                this.selections
 9812                    .all::<OffsetUtf16>(cx)
 9813                    .iter()
 9814                    .zip(ranges_to_replace.iter())
 9815                    .find_map(|(selection, range)| {
 9816                        if selection.id == newest_selection_id {
 9817                            Some(
 9818                                (range.start.0 as isize - selection.head().0 as isize)
 9819                                    ..(range.end.0 as isize - selection.head().0 as isize),
 9820                            )
 9821                        } else {
 9822                            None
 9823                        }
 9824                    })
 9825            });
 9826
 9827            cx.emit(EditorEvent::InputHandled {
 9828                utf16_range_to_replace: range_to_replace,
 9829                text: text.into(),
 9830            });
 9831
 9832            if let Some(new_selected_ranges) = new_selected_ranges {
 9833                this.change_selections(None, cx, |selections| {
 9834                    selections.select_ranges(new_selected_ranges)
 9835                });
 9836                this.backspace(&Default::default(), cx);
 9837            }
 9838
 9839            this.handle_input(text, cx);
 9840        });
 9841
 9842        if let Some(transaction) = self.ime_transaction {
 9843            self.buffer.update(cx, |buffer, cx| {
 9844                buffer.group_until_transaction(transaction, cx);
 9845            });
 9846        }
 9847
 9848        self.unmark_text(cx);
 9849    }
 9850
 9851    fn replace_and_mark_text_in_range(
 9852        &mut self,
 9853        range_utf16: Option<Range<usize>>,
 9854        text: &str,
 9855        new_selected_range_utf16: Option<Range<usize>>,
 9856        cx: &mut ViewContext<Self>,
 9857    ) {
 9858        if !self.input_enabled {
 9859            cx.emit(EditorEvent::InputIgnored { text: text.into() });
 9860            return;
 9861        }
 9862
 9863        let transaction = self.transact(cx, |this, cx| {
 9864            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
 9865                let snapshot = this.buffer.read(cx).read(cx);
 9866                if let Some(relative_range_utf16) = range_utf16.as_ref() {
 9867                    for marked_range in &mut marked_ranges {
 9868                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
 9869                        marked_range.start.0 += relative_range_utf16.start;
 9870                        marked_range.start =
 9871                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
 9872                        marked_range.end =
 9873                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
 9874                    }
 9875                }
 9876                Some(marked_ranges)
 9877            } else if let Some(range_utf16) = range_utf16 {
 9878                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
 9879                Some(this.selection_replacement_ranges(range_utf16, cx))
 9880            } else {
 9881                None
 9882            };
 9883
 9884            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
 9885                let newest_selection_id = this.selections.newest_anchor().id;
 9886                this.selections
 9887                    .all::<OffsetUtf16>(cx)
 9888                    .iter()
 9889                    .zip(ranges_to_replace.iter())
 9890                    .find_map(|(selection, range)| {
 9891                        if selection.id == newest_selection_id {
 9892                            Some(
 9893                                (range.start.0 as isize - selection.head().0 as isize)
 9894                                    ..(range.end.0 as isize - selection.head().0 as isize),
 9895                            )
 9896                        } else {
 9897                            None
 9898                        }
 9899                    })
 9900            });
 9901
 9902            cx.emit(EditorEvent::InputHandled {
 9903                utf16_range_to_replace: range_to_replace,
 9904                text: text.into(),
 9905            });
 9906
 9907            if let Some(ranges) = ranges_to_replace {
 9908                this.change_selections(None, cx, |s| s.select_ranges(ranges));
 9909            }
 9910
 9911            let marked_ranges = {
 9912                let snapshot = this.buffer.read(cx).read(cx);
 9913                this.selections
 9914                    .disjoint_anchors()
 9915                    .iter()
 9916                    .map(|selection| {
 9917                        selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
 9918                    })
 9919                    .collect::<Vec<_>>()
 9920            };
 9921
 9922            if text.is_empty() {
 9923                this.unmark_text(cx);
 9924            } else {
 9925                this.highlight_text::<InputComposition>(
 9926                    marked_ranges.clone(),
 9927                    HighlightStyle {
 9928                        underline: Some(UnderlineStyle {
 9929                            thickness: px(1.),
 9930                            color: None,
 9931                            wavy: false,
 9932                        }),
 9933                        ..Default::default()
 9934                    },
 9935                    cx,
 9936                );
 9937            }
 9938
 9939            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
 9940            let use_autoclose = this.use_autoclose;
 9941            this.set_use_autoclose(false);
 9942            this.handle_input(text, cx);
 9943            this.set_use_autoclose(use_autoclose);
 9944
 9945            if let Some(new_selected_range) = new_selected_range_utf16 {
 9946                let snapshot = this.buffer.read(cx).read(cx);
 9947                let new_selected_ranges = marked_ranges
 9948                    .into_iter()
 9949                    .map(|marked_range| {
 9950                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
 9951                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
 9952                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
 9953                        snapshot.clip_offset_utf16(new_start, Bias::Left)
 9954                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
 9955                    })
 9956                    .collect::<Vec<_>>();
 9957
 9958                drop(snapshot);
 9959                this.change_selections(None, cx, |selections| {
 9960                    selections.select_ranges(new_selected_ranges)
 9961                });
 9962            }
 9963        });
 9964
 9965        self.ime_transaction = self.ime_transaction.or(transaction);
 9966        if let Some(transaction) = self.ime_transaction {
 9967            self.buffer.update(cx, |buffer, cx| {
 9968                buffer.group_until_transaction(transaction, cx);
 9969            });
 9970        }
 9971
 9972        if self.text_highlights::<InputComposition>(cx).is_none() {
 9973            self.ime_transaction.take();
 9974        }
 9975    }
 9976
 9977    fn bounds_for_range(
 9978        &mut self,
 9979        range_utf16: Range<usize>,
 9980        element_bounds: gpui::Bounds<Pixels>,
 9981        cx: &mut ViewContext<Self>,
 9982    ) -> Option<gpui::Bounds<Pixels>> {
 9983        let text_layout_details = self.text_layout_details(cx);
 9984        let style = &text_layout_details.editor_style;
 9985        let font_id = cx.text_system().resolve_font(&style.text.font());
 9986        let font_size = style.text.font_size.to_pixels(cx.rem_size());
 9987        let line_height = style.text.line_height_in_pixels(cx.rem_size());
 9988        let em_width = cx
 9989            .text_system()
 9990            .typographic_bounds(font_id, font_size, 'm')
 9991            .unwrap()
 9992            .size
 9993            .width;
 9994
 9995        let snapshot = self.snapshot(cx);
 9996        let scroll_position = snapshot.scroll_position();
 9997        let scroll_left = scroll_position.x * em_width;
 9998
 9999        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
10000        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
10001            + self.gutter_width;
10002        let y = line_height * (start.row() as f32 - scroll_position.y);
10003
10004        Some(Bounds {
10005            origin: element_bounds.origin + point(x, y),
10006            size: size(em_width, line_height),
10007        })
10008    }
10009}
10010
10011trait SelectionExt {
10012    fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
10013    fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
10014    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
10015    fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
10016        -> Range<u32>;
10017}
10018
10019impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
10020    fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
10021        let start = self.start.to_point(buffer);
10022        let end = self.end.to_point(buffer);
10023        if self.reversed {
10024            end..start
10025        } else {
10026            start..end
10027        }
10028    }
10029
10030    fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
10031        let start = self.start.to_offset(buffer);
10032        let end = self.end.to_offset(buffer);
10033        if self.reversed {
10034            end..start
10035        } else {
10036            start..end
10037        }
10038    }
10039
10040    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
10041        let start = self
10042            .start
10043            .to_point(&map.buffer_snapshot)
10044            .to_display_point(map);
10045        let end = self
10046            .end
10047            .to_point(&map.buffer_snapshot)
10048            .to_display_point(map);
10049        if self.reversed {
10050            end..start
10051        } else {
10052            start..end
10053        }
10054    }
10055
10056    fn spanned_rows(
10057        &self,
10058        include_end_if_at_line_start: bool,
10059        map: &DisplaySnapshot,
10060    ) -> Range<u32> {
10061        let start = self.start.to_point(&map.buffer_snapshot);
10062        let mut end = self.end.to_point(&map.buffer_snapshot);
10063        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
10064            end.row -= 1;
10065        }
10066
10067        let buffer_start = map.prev_line_boundary(start).0;
10068        let buffer_end = map.next_line_boundary(end).0;
10069        buffer_start.row..buffer_end.row + 1
10070    }
10071}
10072
10073impl<T: InvalidationRegion> InvalidationStack<T> {
10074    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
10075    where
10076        S: Clone + ToOffset,
10077    {
10078        while let Some(region) = self.last() {
10079            let all_selections_inside_invalidation_ranges =
10080                if selections.len() == region.ranges().len() {
10081                    selections
10082                        .iter()
10083                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
10084                        .all(|(selection, invalidation_range)| {
10085                            let head = selection.head().to_offset(buffer);
10086                            invalidation_range.start <= head && invalidation_range.end >= head
10087                        })
10088                } else {
10089                    false
10090                };
10091
10092            if all_selections_inside_invalidation_ranges {
10093                break;
10094            } else {
10095                self.pop();
10096            }
10097        }
10098    }
10099}
10100
10101impl<T> Default for InvalidationStack<T> {
10102    fn default() -> Self {
10103        Self(Default::default())
10104    }
10105}
10106
10107impl<T> Deref for InvalidationStack<T> {
10108    type Target = Vec<T>;
10109
10110    fn deref(&self) -> &Self::Target {
10111        &self.0
10112    }
10113}
10114
10115impl<T> DerefMut for InvalidationStack<T> {
10116    fn deref_mut(&mut self) -> &mut Self::Target {
10117        &mut self.0
10118    }
10119}
10120
10121impl InvalidationRegion for SnippetState {
10122    fn ranges(&self) -> &[Range<Anchor>] {
10123        &self.ranges[self.active_index]
10124    }
10125}
10126
10127pub fn diagnostic_block_renderer(diagnostic: Diagnostic, _is_valid: bool) -> RenderBlock {
10128    let (text_without_backticks, code_ranges) = highlight_diagnostic_message(&diagnostic);
10129
10130    Arc::new(move |cx: &mut BlockContext| {
10131        let group_id: SharedString = cx.block_id.to_string().into();
10132
10133        let mut text_style = cx.text_style().clone();
10134        text_style.color = diagnostic_style(diagnostic.severity, true, cx.theme().status());
10135
10136        h_flex()
10137            .id(cx.block_id)
10138            .group(group_id.clone())
10139            .relative()
10140            .size_full()
10141            .pl(cx.gutter_width)
10142            .w(cx.max_width + cx.gutter_width)
10143            .child(div().flex().w(cx.anchor_x - cx.gutter_width).flex_shrink())
10144            .child(div().flex().flex_shrink_0().child(
10145                StyledText::new(text_without_backticks.clone()).with_highlights(
10146                    &text_style,
10147                    code_ranges.iter().map(|range| {
10148                        (
10149                            range.clone(),
10150                            HighlightStyle {
10151                                font_weight: Some(FontWeight::BOLD),
10152                                ..Default::default()
10153                            },
10154                        )
10155                    }),
10156                ),
10157            ))
10158            .child(
10159                IconButton::new(("copy-block", cx.block_id), IconName::Copy)
10160                    .icon_color(Color::Muted)
10161                    .size(ButtonSize::Compact)
10162                    .style(ButtonStyle::Transparent)
10163                    .visible_on_hover(group_id)
10164                    .on_click({
10165                        let message = diagnostic.message.clone();
10166                        move |_click, cx| cx.write_to_clipboard(ClipboardItem::new(message.clone()))
10167                    })
10168                    .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)),
10169            )
10170            .into_any_element()
10171    })
10172}
10173
10174pub fn highlight_diagnostic_message(diagnostic: &Diagnostic) -> (SharedString, Vec<Range<usize>>) {
10175    let mut text_without_backticks = String::new();
10176    let mut code_ranges = Vec::new();
10177
10178    if let Some(source) = &diagnostic.source {
10179        text_without_backticks.push_str(&source);
10180        code_ranges.push(0..source.len());
10181        text_without_backticks.push_str(": ");
10182    }
10183
10184    let mut prev_offset = 0;
10185    let mut in_code_block = false;
10186    for (ix, _) in diagnostic
10187        .message
10188        .match_indices('`')
10189        .chain([(diagnostic.message.len(), "")])
10190    {
10191        let prev_len = text_without_backticks.len();
10192        text_without_backticks.push_str(&diagnostic.message[prev_offset..ix]);
10193        prev_offset = ix + 1;
10194        if in_code_block {
10195            code_ranges.push(prev_len..text_without_backticks.len());
10196            in_code_block = false;
10197        } else {
10198            in_code_block = true;
10199        }
10200    }
10201
10202    (text_without_backticks.into(), code_ranges)
10203}
10204
10205fn diagnostic_style(severity: DiagnosticSeverity, valid: bool, colors: &StatusColors) -> Hsla {
10206    match (severity, valid) {
10207        (DiagnosticSeverity::ERROR, true) => colors.error,
10208        (DiagnosticSeverity::ERROR, false) => colors.error,
10209        (DiagnosticSeverity::WARNING, true) => colors.warning,
10210        (DiagnosticSeverity::WARNING, false) => colors.warning,
10211        (DiagnosticSeverity::INFORMATION, true) => colors.info,
10212        (DiagnosticSeverity::INFORMATION, false) => colors.info,
10213        (DiagnosticSeverity::HINT, true) => colors.info,
10214        (DiagnosticSeverity::HINT, false) => colors.info,
10215        _ => colors.ignored,
10216    }
10217}
10218
10219pub fn styled_runs_for_code_label<'a>(
10220    label: &'a CodeLabel,
10221    syntax_theme: &'a theme::SyntaxTheme,
10222) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
10223    let fade_out = HighlightStyle {
10224        fade_out: Some(0.35),
10225        ..Default::default()
10226    };
10227
10228    let mut prev_end = label.filter_range.end;
10229    label
10230        .runs
10231        .iter()
10232        .enumerate()
10233        .flat_map(move |(ix, (range, highlight_id))| {
10234            let style = if let Some(style) = highlight_id.style(syntax_theme) {
10235                style
10236            } else {
10237                return Default::default();
10238            };
10239            let mut muted_style = style;
10240            muted_style.highlight(fade_out);
10241
10242            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
10243            if range.start >= label.filter_range.end {
10244                if range.start > prev_end {
10245                    runs.push((prev_end..range.start, fade_out));
10246                }
10247                runs.push((range.clone(), muted_style));
10248            } else if range.end <= label.filter_range.end {
10249                runs.push((range.clone(), style));
10250            } else {
10251                runs.push((range.start..label.filter_range.end, style));
10252                runs.push((label.filter_range.end..range.end, muted_style));
10253            }
10254            prev_end = cmp::max(prev_end, range.end);
10255
10256            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
10257                runs.push((prev_end..label.text.len(), fade_out));
10258            }
10259
10260            runs
10261        })
10262}
10263
10264pub(crate) fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
10265    let mut index = 0;
10266    let mut codepoints = text.char_indices().peekable();
10267
10268    std::iter::from_fn(move || {
10269        let start_index = index;
10270        while let Some((new_index, codepoint)) = codepoints.next() {
10271            index = new_index + codepoint.len_utf8();
10272            let current_upper = codepoint.is_uppercase();
10273            let next_upper = codepoints
10274                .peek()
10275                .map(|(_, c)| c.is_uppercase())
10276                .unwrap_or(false);
10277
10278            if !current_upper && next_upper {
10279                return Some(&text[start_index..index]);
10280            }
10281        }
10282
10283        index = text.len();
10284        if start_index < text.len() {
10285            return Some(&text[start_index..]);
10286        }
10287        None
10288    })
10289    .flat_map(|word| word.split_inclusive('_'))
10290    .flat_map(|word| word.split_inclusive('-'))
10291}
10292
10293trait RangeToAnchorExt {
10294    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
10295}
10296
10297impl<T: ToOffset> RangeToAnchorExt for Range<T> {
10298    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
10299        snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
10300    }
10301}