Add documentation to many core editor types (#7919)

vultix and Nathan Sobo created

Hopefully this makes it a bit easier for new contributors to dive into
the codebase :)

Release Notes:

- Improved documentation for many core editor types

---------

Co-authored-by: Nathan Sobo <nathan@zed.dev>

Change summary

crates/clock/src/clock.rs                  |  7 +++
crates/editor/src/display_map.rs           | 14 +++++++
crates/editor/src/display_map/block_map.rs |  3 +
crates/editor/src/display_map/fold_map.rs  |  3 +
crates/editor/src/display_map/inlay_map.rs |  3 +
crates/editor/src/display_map/tab_map.rs   |  3 +
crates/editor/src/display_map/wrap_map.rs  |  3 +
crates/editor/src/editor.rs                |  8 ++++
crates/editor/src/selections_collection.rs |  7 ++-
crates/multi_buffer/src/multi_buffer.rs    | 30 +++++++++++++++++
crates/rope/src/point.rs                   |  1 
crates/rope/src/rope.rs                    |  9 +++++
crates/sum_tree/src/sum_tree.rs            | 42 ++++++++++++++++++++++++
crates/text/src/anchor.rs                  |  3 +
crates/text/src/locator.rs                 |  7 ++++
15 files changed, 138 insertions(+), 5 deletions(-)

Detailed changes

crates/clock/src/clock.rs ๐Ÿ”—

@@ -4,16 +4,21 @@ use std::{
     fmt, iter,
 };
 
+/// A unique identifier for each distributed node
 pub type ReplicaId = u16;
+
+/// A [Lamport sequence number](https://en.wikipedia.org/wiki/Lamport_timestamp),
 pub type Seq = u32;
 
+/// A [Lamport timestamp](https://en.wikipedia.org/wiki/Lamport_timestamp),
+/// used to determine the ordering of events in the editor.
 #[derive(Clone, Copy, Default, Eq, Hash, PartialEq)]
 pub struct Lamport {
     pub replica_id: ReplicaId,
     pub value: Seq,
 }
 
-/// A vector clock
+/// A [vector clock](https://en.wikipedia.org/wiki/Vector_clock)
 #[derive(Clone, Default, Hash, Eq, PartialEq)]
 pub struct Global(SmallVec<[u32; 8]>);
 

crates/editor/src/display_map.rs ๐Ÿ”—

@@ -67,15 +67,27 @@ pub trait ToDisplayPoint {
 type TextHighlights = TreeMap<Option<TypeId>, Arc<(HighlightStyle, Vec<Range<Anchor>>)>>;
 type InlayHighlights = BTreeMap<TypeId, HashMap<InlayId, (HighlightStyle, InlayHighlight)>>;
 
+/// Decides how text in a [`MultiBuffer`] should be displayed in a buffer, handling inlay hints,
+/// folding, hard tabs, soft wrapping, custom blocks (like diagnostics), and highlighting.
+///
+/// See the [module level documentation](self) for more information.
 pub struct DisplayMap {
+    /// The buffer that we are displaying.
     buffer: Model<MultiBuffer>,
     buffer_subscription: BufferSubscription,
-    fold_map: FoldMap,
+    /// Decides where the [`Inlay`]s should be displayed.
     inlay_map: InlayMap,
+    /// Decides where the fold indicators should be and tracks parts of a source file that are currently folded.
+    fold_map: FoldMap,
+    /// Keeps track of hard tabs in a buffer.
     tab_map: TabMap,
+    /// Handles soft wrapping.
     wrap_map: Model<WrapMap>,
+    /// Tracks custom blocks such as diagnostics that should be displayed within buffer.
     block_map: BlockMap,
+    /// Regions of text that should be highlighted.
     text_highlights: TextHighlights,
+    /// Regions of inlays that should be highlighted.
     inlay_highlights: InlayHighlights,
     pub clip_at_line_ends: bool,
 }

crates/editor/src/display_map/block_map.rs ๐Ÿ”—

@@ -22,6 +22,9 @@ use text::Edit;
 
 const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
 
+/// Tracks custom blocks such as diagnostics that should be displayed within buffer.
+///
+/// See the [`display_map` module documentation](crate::display_map) for more information.
 pub struct BlockMap {
     next_block_id: AtomicUsize,
     wrap_snapshot: RefCell<WrapSnapshot>,

crates/editor/src/display_map/fold_map.rs ๐Ÿ”—

@@ -178,6 +178,9 @@ impl<'a> FoldMapWriter<'a> {
     }
 }
 
+/// Decides where the fold indicators should be; also tracks parts of a source file that are currently folded.
+///
+/// See the [`display_map` module documentation](crate::display_map) for more information.
 pub(crate) struct FoldMap {
     snapshot: FoldSnapshot,
     ellipses_color: Option<Hsla>,

crates/editor/src/display_map/inlay_map.rs ๐Ÿ”—

@@ -16,6 +16,9 @@ use text::{Patch, Rope};
 
 use super::Highlights;
 
+/// Decides where the [`Inlay`]s should be displayed.
+///
+/// See the [`display_map` module documentation](crate::display_map) for more information.
 pub struct InlayMap {
     snapshot: InlaySnapshot,
     inlays: Vec<Inlay>,

crates/editor/src/display_map/tab_map.rs ๐Ÿ”—

@@ -9,6 +9,9 @@ use sum_tree::Bias;
 
 const MAX_EXPANSION_COLUMN: u32 = 256;
 
+/// Keeps track of hard tabs in a text buffer.
+///
+/// See the [`display_map` module documentation](crate::display_map) for more information.
 pub struct TabMap(TabSnapshot);
 
 impl TabMap {

crates/editor/src/display_map/wrap_map.rs ๐Ÿ”—

@@ -15,6 +15,9 @@ use text::Patch;
 pub use super::tab_map::TextSummary;
 pub type WrapEdit = text::Edit<u32>;
 
+/// Handles soft wrapping of text.
+///
+/// See the [`display_map` module documentation](crate::display_map) for more information.
 pub struct WrapMap {
     snapshot: WrapSnapshot,
     pending_edits: VecDeque<(TabSnapshot, Vec<TabEdit>)>,

crates/editor/src/editor.rs ๐Ÿ”—

@@ -290,7 +290,7 @@ pub enum SelectPhase {
 }
 
 #[derive(Clone, Debug)]
-pub(crate) enum SelectMode {
+pub enum SelectMode {
     Character,
     Word(Range<Anchor>),
     Line(Range<Anchor>),
@@ -349,10 +349,16 @@ type CompletionId = usize;
 type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<Range<Anchor>>);
 type InlayBackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<InlayHighlight>);
 
+/// Zed's primary text input `View`, allowing users to edit a [`MultiBuffer`]
+///
+/// See the [module level documentation](self) for more information.
 pub struct Editor {
     handle: WeakView<Self>,
     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.
     display_map: Model<DisplayMap>,
     pub selections: SelectionsCollection,
     pub scroll_manager: ScrollManager,

crates/editor/src/selections_collection.rs ๐Ÿ”—

@@ -29,8 +29,11 @@ pub struct SelectionsCollection {
     buffer: Model<MultiBuffer>,
     pub next_selection_id: usize,
     pub line_mode: bool,
-    disjoint: Arc<[Selection<Anchor>]>,
-    pending: Option<PendingSelection>,
+    /// The non-pending, non-overlapping selections.
+    /// The [SelectionsCollection::pending] selection could possibly overlap these
+    pub disjoint: Arc<[Selection<Anchor>]>,
+    /// A pending selection, such as when the mouse is being dragged
+    pub pending: Option<PendingSelection>,
 }
 
 impl SelectionsCollection {

crates/multi_buffer/src/multi_buffer.rs ๐Ÿ”—

@@ -47,10 +47,17 @@ const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
 #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct ExcerptId(usize);
 
+/// One or more [`Buffers`](Buffer) being edited in a single view.
+///
+/// See <https://zed.dev/features#multi-buffers>
 pub struct MultiBuffer {
+    /// A snapshot of the [`Excerpt`]s in the MultiBuffer.
+    /// Use [`MultiBuffer::snapshot`] to get a up-to-date snapshot.
     snapshot: RefCell<MultiBufferSnapshot>,
+    /// Contains the state of the buffers being edited
     buffers: RefCell<HashMap<BufferId, BufferState>>,
     subscriptions: Topic,
+    /// If true, the multi-buffer only contains a single [`Buffer`] and a single [`Excerpt`]
     singleton: bool,
     replica_id: ReplicaId,
     history: History,
@@ -135,6 +142,7 @@ struct BufferState {
     _subscriptions: [gpui::Subscription; 2],
 }
 
+/// The contents of a [`MultiBuffer`] at a single point in time.
 #[derive(Clone, Default)]
 pub struct MultiBufferSnapshot {
     singleton: bool,
@@ -149,22 +157,36 @@ pub struct MultiBufferSnapshot {
     has_conflict: bool,
 }
 
+/// A boundary between [`Excerpt`]s in a [`MultiBuffer`]
 pub struct ExcerptBoundary {
     pub id: ExcerptId,
+    /// The row in the `MultiBuffer` where the boundary is located
     pub row: u32,
     pub buffer: BufferSnapshot,
     pub range: ExcerptRange<text::Anchor>,
+    /// It's possible to have multiple excerpts in the same buffer,
+    /// and they are rendered together without a new File header.
+    ///
+    /// This flag indicates that the excerpt is the first one in the buffer.
     pub starts_new_buffer: bool,
 }
 
+/// A slice into a [`Buffer`] that is being edited in a [`MultiBuffer`].
 #[derive(Clone)]
 struct Excerpt {
+    /// The unique identifier for this excerpt
     id: ExcerptId,
+    /// The location of the excerpt in the [`MultiBuffer`]
     locator: Locator,
+    /// The buffer being excerpted
     buffer_id: BufferId,
+    /// A snapshot of the buffer being excerpted
     buffer: BufferSnapshot,
+    /// The range of the buffer to be shown in the excerpt
     range: ExcerptRange<text::Anchor>,
+    /// The last row in the excerpted slice of the buffer
     max_buffer_row: u32,
+    /// A summary of the text in the excerpt
     text_summary: TextSummary,
     has_trailing_newline: bool,
 }
@@ -175,16 +197,23 @@ struct ExcerptIdMapping {
     locator: Locator,
 }
 
+/// A range of text from a single [`Buffer`], to be shown as an [`Excerpt`].
+/// These ranges are relative to the buffer itself
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct ExcerptRange<T> {
+    /// The full range of text to be shown in the excerpt.
     pub context: Range<T>,
+    /// The primary range of text to be highlighted in the excerpt.
+    /// In a multi-buffer search, this would be the text that matched the search
     pub primary: Option<Range<T>>,
 }
 
 #[derive(Clone, Debug, Default)]
 struct ExcerptSummary {
     excerpt_id: ExcerptId,
+    /// The location of the last [`Excerpt`] being summarized
     excerpt_locator: Locator,
+    /// The maximum row of the [`Excerpt`]s being summarized
     max_buffer_row: u32,
     text: TextSummary,
 }
@@ -307,6 +336,7 @@ impl MultiBuffer {
         self.replica_id
     }
 
+    /// Returns an up-to-date snapshot of the MultiBuffer.
     pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot {
         self.sync(cx);
         self.snapshot.borrow().clone()

crates/rope/src/point.rs ๐Ÿ”—

@@ -3,6 +3,7 @@ use std::{
     ops::{Add, AddAssign, Sub},
 };
 
+/// A zero-indexed point in a text buffer consisting of a row and column.
 #[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash)]
 pub struct Point {
     pub row: u32,

crates/rope/src/rope.rs ๐Ÿ”—

@@ -953,15 +953,24 @@ impl sum_tree::Summary for ChunkSummary {
     }
 }
 
+/// Summary of a string of text.
 #[derive(Clone, Debug, Default, Eq, PartialEq)]
 pub struct TextSummary {
+    /// Length in UTF-8
     pub len: usize,
+    /// Length in UTF-16 code units
     pub len_utf16: OffsetUtf16,
+    /// A point representing the number of lines and the length of the last line
     pub lines: Point,
+    /// How many `char`s are in the first line
     pub first_line_chars: u32,
+    /// How many `char`s are in the last line
     pub last_line_chars: u32,
+    /// How many UTF-16 code units are in the last line
     pub last_line_len_utf16: u32,
+    /// The row idx of the longest row
     pub longest_row: u32,
+    /// How many `char`s are in the longest row
     pub longest_row_chars: u32,
 }
 

crates/sum_tree/src/sum_tree.rs ๐Ÿ”—

@@ -14,24 +14,39 @@ pub const TREE_BASE: usize = 2;
 #[cfg(not(test))]
 pub const TREE_BASE: usize = 6;
 
+/// An item that can be stored in a [`SumTree`]
+///
+/// Must be summarized by a type that implements [`Summary`]
 pub trait Item: Clone {
     type Summary: Summary;
 
     fn summary(&self) -> Self::Summary;
 }
 
+/// An [`Item`] whose summary has a specific key that can be used to identify it
 pub trait KeyedItem: Item {
     type Key: for<'a> Dimension<'a, Self::Summary> + Ord;
 
     fn key(&self) -> Self::Key;
 }
 
+/// A type that describes the Sum of all [`Item`]s in a subtree of the [`SumTree`]
+///
+/// Each Summary type can have multiple [`Dimensions`] that it measures,
+/// which can be used to navigate the tree
 pub trait Summary: Default + Clone + fmt::Debug {
     type Context;
 
     fn add_summary(&mut self, summary: &Self, cx: &Self::Context);
 }
 
+/// Each [`Summary`] type can have more than one [`Dimension`] type that it measures.
+///
+/// You can use dimensions to seek to a specific location in the [`SumTree`]
+///
+/// # Example:
+/// Zed's rope has a `TextSummary` type that summarizes lines, characters, and bytes.
+/// Each of these are different dimensions we may want to seek to
 pub trait Dimension<'a, S: Summary>: Clone + fmt::Debug + Default {
     fn add_summary(&mut self, _summary: &'a S, _: &S::Context);
 
@@ -97,10 +112,33 @@ impl<D> fmt::Debug for End<D> {
     }
 }
 
+/// Bias is used to settle ambiguities when determining positions in an ordered sequence.
+///
+/// The primary use case is for text, where Bias influences
+/// which character an offset or anchor is associated with.
+///
+/// # Examples
+/// Given the buffer `Aห‡BCD`:
+/// - The offset of the cursor is 1
+/// - [Bias::Left] would attach the cursor to the character `A`
+/// - [Bias::Right] would attach the cursor to the character `B`
+///
+/// Given the buffer `AยซBCห‡ยปD`:
+/// - The offset of the cursor is 3, and the selection is from 1 to 3
+/// - The left anchor of the selection has [Bias::Right], attaching it to the character `B`
+/// - The right anchor of the selection has [Bias::Left], attaching it to the character `C`
+///
+/// Given the buffer `{ห‡<...>`, where `<...>` is a folded region:
+/// - The display offset of the cursor is 1, but the offset in the buffer is determined by the bias
+/// - [Bias::Left] would attach the cursor to the character `{`, with a buffer offset of 1
+/// - [Bias::Right] would attach the cursor to the first character of the folded region,
+///   and the buffer offset would be the offset of the first character of the folded region
 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Hash, Default)]
 pub enum Bias {
+    /// Attach to the character on the left
     #[default]
     Left,
+    /// Attach to the character on the right
     Right,
 }
 
@@ -113,6 +151,10 @@ impl Bias {
     }
 }
 
+/// A B-tree where each leaf node contains an [`Item`] of type `T`,
+/// and each internal node contains a [`Summary`] of the items in its subtree.
+///
+/// Any [`Dimension`] supported by the [`Summary`] type can be used to seek to a specific location in the tree.
 #[derive(Debug, Clone)]
 pub struct SumTree<T: Item>(Arc<Node<T>>);
 

crates/text/src/anchor.rs ๐Ÿ”—

@@ -6,10 +6,13 @@ use anyhow::Result;
 use std::{cmp::Ordering, fmt::Debug, ops::Range};
 use sum_tree::Bias;
 
+/// A timestamped position in a buffer
 #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Default)]
 pub struct Anchor {
     pub timestamp: clock::Lamport,
+    /// The byte offset in the buffer
     pub offset: usize,
+    /// Describes which character the anchor is biased towards
     pub bias: Bias,
     pub buffer_id: Option<BufferId>,
 }

crates/text/src/locator.rs ๐Ÿ”—

@@ -7,6 +7,13 @@ lazy_static! {
     static ref MAX: Locator = Locator::max();
 }
 
+/// An identifier for a position in a ordered collection.
+///
+/// Allows prepending and appending without needing to renumber existing locators
+/// using `Locator::between(lhs, rhs)`.
+///
+/// The initial location for a collection should be `Locator::between(Locator::min(), Locator::max())`,
+/// leaving room for items to be inserted before and after it.
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Locator(SmallVec<[u64; 4]>);