10799 lines · 400.5 KB · Rust
RawDownload
#![allow(rustdoc::private_intra_doc_links)]//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.//! It comes in different flavors: single line, multiline and a fixed height one.//!//! Editor contains of multiple large submodules://! * [`element`] — the place where all rendering happens//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.//!//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).//!//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behaviour.pub mod actions;mod blink_manager;pub mod display_map;mod editor_settings;mod element;mod inlay_hint_cache; mod debounced_delay;mod git;mod highlight_matching_bracket;mod hover_links;mod hover_popover;pub mod items;mod mouse_context_menu;pub mod movement;mod persistence;mod rust_analyzer_ext;pub mod scroll;mod selections_collection; #[cfg(test)]mod editor_tests;#[cfg(any(test, feature = "test-support"))]pub mod test;use ::git::diff::{DiffHunk, DiffHunkStatus};pub(crate) use actions::*;use aho_corasick::AhoCorasick;use anyhow::{anyhow, Context as _, Result};use blink_manager::BlinkManager;use client::{Collaborator, ParticipantIndex};use clock::ReplicaId;use collections::{hash_map, BTreeMap, Bound, HashMap, HashSet, VecDeque};use convert_case::{Case, Casing};use copilot::Copilot;use debounced_delay::DebouncedDelay;pub use display_map::DisplayPoint;use display_map::*;pub use editor_settings::EditorSettings;use element::LineWithInvisibles;pub use element::{    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,};use futures::FutureExt;use fuzzy::{StringMatch, StringMatchCandidate};use git::diff_hunk_to_display;use gpui::{    div, impl_actions, point, prelude::*, px, relative, rems, size, uniform_list, Action,    AnyElement, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Context,    DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusableView, FontId, FontStyle,    FontWeight, HighlightStyle, Hsla, InteractiveText, KeyContext, Model, MouseButton,    ParentElement, Pixels, Render, SharedString, StrikethroughStyle, Styled, StyledText,    Subscription, Task, TextStyle, UnderlineStyle, UniformListScrollHandle, View, ViewContext,    ViewInputHandler, VisualContext, WeakView, WhiteSpace, WindowContext,};use highlight_matching_bracket::refresh_matching_bracket_highlights;use hover_popover::{hide_hover, HoverState};use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};pub use items::MAX_TAB_TITLE_LEN;use itertools::Itertools;use language::{char_kind, CharKind};use language::{    language_settings::{self, all_language_settings, InlayHintSettings},    markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CodeAction,    CodeLabel, Completion, CursorShape, Diagnostic, Documentation, IndentKind, IndentSize,    Language, OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId,}; use hover_links::{HoverLink, HoveredLinkState, InlayHighlight};use lsp::{DiagnosticSeverity, LanguageServerId};use mouse_context_menu::MouseContextMenu;use movement::TextLayoutDetails;use multi_buffer::ToOffsetUtf16;pub use multi_buffer::{    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,    ToPoint,};use ordered_float::OrderedFloat;use parking_lot::{Mutex, RwLock};use project::project_settings::{GitGutterSetting, ProjectSettings};use project::Item;use project::{FormatTrigger, Location, Project, ProjectPath, ProjectTransaction};use rand::prelude::*;use rpc::proto::*;use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};use serde::{Deserialize, Serialize};use settings::{Settings, SettingsStore};use smallvec::SmallVec;use snippet::Snippet;use std::ops::Not as _;use std::{    any::TypeId,    borrow::Cow,    cmp::{self, Ordering, Reverse},    mem,    num::NonZeroU32,    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},    path::Path,    sync::Arc,    time::{Duration, Instant},};pub use sum_tree::Bias;use text::{BufferId, OffsetUtf16, Rope};use theme::{    observe_buffer_font_size_adjustment, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme,    ThemeColors, ThemeSettings,};use ui::{    h_flex, prelude::*, ButtonSize, ButtonStyle, IconButton, IconName, IconSize, ListItem, Popover,    Tooltip,};use util::{maybe, post_inc, RangeExt, ResultExt, TryFutureExt};use workspace::Toast;use workspace::{    searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId,}; use crate::hover_links::find_url; const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);const MAX_LINE_LEN: usize = 1024;const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;const MAX_SELECTION_HISTORY_LEN: usize = 1024;const COPILOT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);#[doc(hidden)]pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);#[doc(hidden)]pub const DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75); pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(2); pub fn render_parsed_markdown(    element_id: impl Into<ElementId>,    parsed: &language::ParsedMarkdown,    editor_style: &EditorStyle,    workspace: Option<WeakView<Workspace>>,    cx: &mut ViewContext<Editor>,) -> InteractiveText {    let code_span_background_color = cx        .theme()        .colors()        .editor_document_highlight_read_background;     let highlights = gpui::combine_highlights(        parsed.highlights.iter().filter_map(|(range, highlight)| {            let highlight = highlight.to_highlight_style(&editor_style.syntax)?;            Some((range.clone(), highlight))        }),        parsed            .regions            .iter()            .zip(&parsed.region_ranges)            .filter_map(|(region, range)| {                if region.code {                    Some((                        range.clone(),                        HighlightStyle {                            background_color: Some(code_span_background_color),                            ..Default::default()                        },                    ))                } else {                    None                }            }),    );     let mut links = Vec::new();    let mut link_ranges = Vec::new();    for (range, region) in parsed.region_ranges.iter().zip(&parsed.regions) {        if let Some(link) = region.link.clone() {            links.push(link);            link_ranges.push(range.clone());        }    }     InteractiveText::new(        element_id,        StyledText::new(parsed.text.clone()).with_highlights(&editor_style.text, highlights),    )    .on_click(link_ranges, move |clicked_range_ix, cx| {        match &links[clicked_range_ix] {            markdown::Link::Web { url } => cx.open_url(url),            markdown::Link::Path { path } => {                if let Some(workspace) = &workspace {                    _ = workspace.update(cx, |workspace, cx| {                        workspace.open_abs_path(path.clone(), false, cx).detach();                    });                }            }        }    })} #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]pub(crate) enum InlayId {    Suggestion(usize),    Hint(usize),} impl InlayId {    fn id(&self) -> usize {        match self {            Self::Suggestion(id) => *id,            Self::Hint(id) => *id,        }    }} enum DocumentHighlightRead {}enum DocumentHighlightWrite {}enum InputComposition {} #[derive(Copy, Clone, PartialEq, Eq)]pub enum Direction {    Prev,    Next,} pub fn init_settings(cx: &mut AppContext) {    EditorSettings::register(cx);} pub fn init(cx: &mut AppContext) {    init_settings(cx);     workspace::register_project_item::<Editor>(cx);    workspace::register_followable_item::<Editor>(cx);    workspace::register_deserializable_item::<Editor>(cx);    cx.observe_new_views(        |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {            workspace.register_action(Editor::new_file);            workspace.register_action(Editor::new_file_in_direction);        },    )    .detach();     cx.on_action(move |_: &workspace::NewFile, cx| {        let app_state = workspace::AppState::global(cx);        if let Some(app_state) = app_state.upgrade() {            workspace::open_new(app_state, cx, |workspace, cx| {                Editor::new_file(workspace, &Default::default(), cx)            })            .detach();        }    });    cx.on_action(move |_: &workspace::NewWindow, cx| {        let app_state = workspace::AppState::global(cx);        if let Some(app_state) = app_state.upgrade() {            workspace::open_new(app_state, cx, |workspace, cx| {                Editor::new_file(workspace, &Default::default(), cx)            })            .detach();        }    });} trait InvalidationRegion {    fn ranges(&self) -> &[Range<Anchor>];} #[derive(Clone, Debug, PartialEq)]pub enum SelectPhase {    Begin {        position: DisplayPoint,        add: bool,        click_count: usize,    },    BeginColumnar {        position: DisplayPoint,        goal_column: u32,    },    Extend {        position: DisplayPoint,        click_count: usize,    },    Update {        position: DisplayPoint,        goal_column: u32,        scroll_delta: gpui::Point<f32>,    },    End,} #[derive(Clone, Debug)]pub enum SelectMode {    Character,    Word(Range<Anchor>),    Line(Range<Anchor>),    All,} #[derive(Copy, Clone, PartialEq, Eq, Debug)]pub enum EditorMode {    SingleLine,    AutoHeight { max_lines: usize },    Full,} #[derive(Clone, Debug)]pub enum SoftWrap {    None,    EditorWidth,    Column(u32),} #[derive(Clone)]pub struct EditorStyle {    pub background: Hsla,    pub local_player: PlayerColor,    pub text: TextStyle,    pub scrollbar_width: Pixels,    pub syntax: Arc<SyntaxTheme>,    pub status: StatusColors,    pub inlay_hints_style: HighlightStyle,    pub suggestions_style: HighlightStyle,} impl Default for EditorStyle {    fn default() -> Self {        Self {            background: Hsla::default(),            local_player: PlayerColor::default(),            text: TextStyle::default(),            scrollbar_width: Pixels::default(),            syntax: Default::default(),            // HACK: Status colors don't have a real default.            // We should look into removing the status colors from the editor            // style and retrieve them directly from the theme.            status: StatusColors::dark(),            inlay_hints_style: HighlightStyle::default(),            suggestions_style: HighlightStyle::default(),        }    }} type CompletionId = usize; // type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>; type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<Range<Anchor>>); /// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`]////// See the [module level documentation](self) for more information.pub struct Editor {    focus_handle: FocusHandle,    /// The text buffer being edited    buffer: Model<MultiBuffer>,    /// Map of how text in the buffer should be displayed.    /// Handles soft wraps, folds, fake inlay text insertions, etc.    pub display_map: Model<DisplayMap>,    pub selections: SelectionsCollection,    pub scroll_manager: ScrollManager,    columnar_selection_tail: Option<Anchor>,    add_selections_state: Option<AddSelectionsState>,    select_next_state: Option<SelectNextState>,    select_prev_state: Option<SelectNextState>,    selection_history: SelectionHistory,    autoclose_regions: Vec<AutocloseRegion>,    snippet_stack: InvalidationStack<SnippetState>,    select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,    ime_transaction: Option<TransactionId>,    active_diagnostics: Option<ActiveDiagnosticGroup>,    soft_wrap_mode_override: Option<language_settings::SoftWrap>,    project: Option<Model<Project>>,    completion_provider: Option<Box<dyn CompletionProvider>>,    collaboration_hub: Option<Box<dyn CollaborationHub>>,    blink_manager: Model<BlinkManager>,    show_cursor_names: bool,    hovered_cursors: HashMap<HoveredCursor, Task<()>>,    pub show_local_selections: bool,    mode: EditorMode,    show_breadcrumbs: bool,    show_gutter: bool,    show_wrap_guides: Option<bool>,    placeholder_text: Option<Arc<str>>,    highlight_order: usize,    highlighted_rows: HashMap<TypeId, Vec<(usize, Range<Anchor>, Hsla)>>,    background_highlights: BTreeMap<TypeId, BackgroundHighlight>,    nav_history: Option<ItemNavHistory>,    context_menu: RwLock<Option<ContextMenu>>,    mouse_context_menu: Option<MouseContextMenu>,    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,    find_all_references_task_sources: Vec<Anchor>,    next_completion_id: CompletionId,    completion_documentation_pre_resolve_debounce: DebouncedDelay,    available_code_actions: Option<(Model<Buffer>, Arc<[CodeAction]>)>,    code_actions_task: Option<Task<()>>,    document_highlights_task: Option<Task<()>>,    pending_rename: Option<RenameState>,    searchable: bool,    cursor_shape: CursorShape,    collapse_matches: bool,    autoindent_mode: Option<AutoindentMode>,    workspace: Option<(WeakView<Workspace>, WorkspaceId)>,    keymap_context_layers: BTreeMap<TypeId, KeyContext>,    input_enabled: bool,    use_modal_editing: bool,    read_only: bool,    leader_peer_id: Option<PeerId>,    remote_id: Option<ViewId>,    hover_state: HoverState,    gutter_hovered: bool,    hovered_link_state: Option<HoveredLinkState>,    copilot_state: CopilotState,    inlay_hint_cache: InlayHintCache,    next_inlay_id: usize,    _subscriptions: Vec<Subscription>,    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,    gutter_width: Pixels,    pub vim_replace_map: HashMap<Range<usize>, String>,    style: Option<EditorStyle>,    editor_actions: Vec<Box<dyn Fn(&mut ViewContext<Self>)>>,    show_copilot_suggestions: bool,    use_autoclose: bool,    auto_replace_emoji_shortcode: bool,    custom_context_menu: Option<        Box<            dyn 'static                + Fn(&mut Self, DisplayPoint, &mut ViewContext<Self>) -> Option<View<ui::ContextMenu>>,        >,    >,} pub struct EditorSnapshot {    pub mode: EditorMode,    show_gutter: bool,    pub display_snapshot: DisplaySnapshot,    pub placeholder_text: Option<Arc<str>>,    is_focused: bool,    scroll_anchor: ScrollAnchor,    ongoing_scroll: OngoingScroll,} pub struct GutterDimensions {    pub left_padding: Pixels,    pub right_padding: Pixels,    pub width: Pixels,    pub margin: Pixels,} impl Default for GutterDimensions {    fn default() -> Self {        Self {            left_padding: Pixels::ZERO,            right_padding: Pixels::ZERO,            width: Pixels::ZERO,            margin: Pixels::ZERO,        }    }} #[derive(Debug)]pub struct RemoteSelection {    pub replica_id: ReplicaId,    pub selection: Selection<Anchor>,    pub cursor_shape: CursorShape,    pub peer_id: PeerId,    pub line_mode: bool,    pub participant_index: Option<ParticipantIndex>,    pub user_name: Option<SharedString>,} #[derive(Clone, Debug)]struct SelectionHistoryEntry {    selections: Arc<[Selection<Anchor>]>,    select_next_state: Option<SelectNextState>,    select_prev_state: Option<SelectNextState>,    add_selections_state: Option<AddSelectionsState>,} enum SelectionHistoryMode {    Normal,    Undoing,    Redoing,} #[derive(Clone, PartialEq, Eq, Hash)]struct HoveredCursor {    replica_id: u16,    selection_id: usize,} 

Lines 1–500 of 10799.