editor.rs

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