diff --git a/crates/dock/src/dock_area.rs b/crates/dock/src/dock_area.rs index 7b3f3df..2c604cb 100644 --- a/crates/dock/src/dock_area.rs +++ b/crates/dock/src/dock_area.rs @@ -27,11 +27,7 @@ use crate::tiles::SignedTilesSkin; use crate::{TAB_BAR_HEIGHT, panel_handle}; /// What every part of the skin reads, and the dock area it belongs to. -/// -/// The renderer is the only skin-owned object in the picture, so the settings -/// the old `DockArea` carried live here. It is shared by reference with the -/// per-container renderers, which are built once each and outlive any one -/// frame. +/// Shared by reference with the per-container renderers. pub(crate) struct SkinShared { area: WeakEntity, toggle_button_visible: Cell, @@ -201,10 +197,9 @@ impl DockAreaRenderer for SignedDockSkin { .into_any_element() } - /// The "unknown panel" message the old `InvalidPanel` drew. - /// - /// It answers `dump` with the state it was handed, so a layout written by - /// a build that knows the panel survives a load and save here. + /// The "unknown panel" message the old `InvalidPanel` drew. It answers + /// `dump` with the state it was handed, so a layout written by a build + /// that knows the panel survives a load and save here. fn build_placeholder( &self, state: &PanelState, @@ -246,12 +241,10 @@ impl SignedDockSkin { } } -/// Turns the window's mouse stream into dock resizing. -/// -/// A resize is driven by pointer moves that land anywhere in the window, not -/// only on the handle, so it cannot be expressed as a listener on the handle -/// itself. This element paints nothing and exists for its `paint` hook, which -/// is the only place a window-level mouse listener can be registered. +/// Turns the window's mouse stream into dock resizing. A resize is driven +/// by pointer moves anywhere in the window, so this paints nothing and +/// exists for its `paint` hook — the only place a window-level mouse +/// listener can be registered. struct DockResizeTracker { dock: DockContext, shared: Rc, @@ -317,10 +310,10 @@ impl Element for DockResizeTracker { if !phase.bubble() || shared.resizing_dock().get() != Some(placement) { return; } - // Dragging a closed dock's handle reopens it, as the old dock - // did. The live state is read rather than the render-time - // snapshot in `dock`, which would still say closed for the - // rest of the frame and toggle it shut again on the next move. + // Dragging a closed dock's handle reopens it. The live + // state is read rather than the render-time snapshot in + // `dock`, which would still say closed for the rest of the + // frame and toggle it shut again on the next move. let open = shared .area() .upgrade() diff --git a/crates/dock/src/invalid_panel.rs b/crates/dock/src/invalid_panel.rs index da78f36..85675a5 100644 --- a/crates/dock/src/invalid_panel.rs +++ b/crates/dock/src/invalid_panel.rs @@ -7,12 +7,10 @@ use gpui_component::ActiveTheme as _; use crate::Panel; -/// Stands in for a panel this build cannot construct — one whose `panel_name` -/// no [`PanelRegistry`](gpui_base::dock::PanelRegistry) builder answers to. -/// -/// It reports the original [`PanelState`] from -/// [`dump`](gpui_base::dock::Panel::dump), so a layout written by a build that -/// knows the panel survives a load and a save here rather than losing it. +/// Stands in for a panel this build cannot construct. It reports the +/// original [`PanelState`] from [`dump`](gpui_base::dock::Panel::dump), so +/// a layout written by a build that knows the panel survives a load and +/// save here. pub(crate) struct InvalidPanel { name: SharedString, focus_handle: FocusHandle, diff --git a/crates/dock/src/lib.rs b/crates/dock/src/lib.rs index 16f2192..b919f15 100644 --- a/crates/dock/src/lib.rs +++ b/crates/dock/src/lib.rs @@ -1,12 +1,10 @@ //! The Signed dock skin. //! -//! The dock engine lives upstream: `gpui_base::dock` owns the layout tree, -//! the drags, the zoom and the persistence, and `gpui_component::dock` -//! supplies the default appearance. This crate is the appearance the app -//! used to vendor from gpui-component — a 44px tab bar that doubles as the -//! window title bar, with pill tabs, window controls, title-bar dragging and -//! previous/next tab buttons — re-implemented against upstream's renderer -//! traits. +//! The dock engine lives upstream (`gpui_base::dock` owns the layout tree, +//! drags, zoom and persistence); this crate is the appearance the app used +//! to vendor from gpui-component — a 44px tab bar that doubles as the +//! window title bar, with pill tabs, window controls, title-bar dragging +//! and previous/next tab buttons. //! //! Everything `gpui_component::dock` exports is re-exported here, so the app //! keeps importing the dock from a single place. diff --git a/crates/dock/src/tab_panel.rs b/crates/dock/src/tab_panel.rs index 8d0bf79..bcf135a 100644 --- a/crates/dock/src/tab_panel.rs +++ b/crates/dock/src/tab_panel.rs @@ -84,11 +84,9 @@ impl Render for DragPanelPreview { } /// Where the zoom affordance goes for the group's displayed panel, or `None` -/// when there is none to offer. -/// -/// Two questions, and both have to be asked. [`Panel::zoom_control`] says -/// *where* the control appears; [`gpui_base::dock::Panel::zoomable`] says -/// whether zooming happens at all, and base refuses a zoom that fails it. +/// when there is none to offer. Both [`Panel::zoom_control`] (where) and +/// [`gpui_base::dock::Panel::zoomable`] (whether) must pass; base refuses a +/// zoom that fails the latter. fn zoom_control(group: &TabGroupContext, cx: &App) -> Option { let panel = group.active_panel()?; panel @@ -122,11 +120,8 @@ fn right_top_group(node: &PaneNode) -> Option { } } -/// One tab group's appearance. -/// -/// Built per group — `DockAreaRenderer::tab_group_renderer` is called once -/// per container — so the tab bar's scroll position and the measured -/// title-bar geometry belong to the group they describe. +/// One tab group's appearance. Built once per container, so the tab bar's +/// scroll position and measured title-bar geometry belong to the group. pub(crate) struct SignedTabGroupSkin { shared: Rc, scroll_handle: ScrollHandle, @@ -177,9 +172,8 @@ impl SignedTabGroupSkin { /// The bottom or right dock whose root tab group this group is, if any. /// /// Base bars a dock's only group from being dragged or closed, so the - /// dock cannot be emptied. A bottom/right panel is supposed to be - /// closable and movable, though — the vendored dock allowed exactly that - /// — so the skin recognizes the group and routes around the bar. + /// dock cannot be emptied — but a bottom/right panel is supposed to be + /// closable, so the skin routes around the bar for these groups. fn is_dock_root_group(&self, group: &TabGroupContext, cx: &App) -> Option { let area = self.shared.area().upgrade()?; let area = area.read(cx); @@ -270,9 +264,7 @@ impl SignedTabGroupSkin { } /// The previous/next tab buttons shown in the tab bar's leading prefix. - /// - /// Unlike the dock toggle button they always render, but are disabled at - /// the ends of the tab strip (or while the panel is collapsed). + /// Always rendered, disabled at the ends of the strip (or collapsed). fn render_prev_next_tab_buttons( &self, group: &TabGroupContext, @@ -405,10 +397,9 @@ impl SignedTabGroupSkin { ) } - /// One tab of the pill strip. - /// - /// While collapsed, tabs lose the active style and all interactions, and - /// the strip becomes the way a closed bottom dock is opened again. + /// One tab of the pill strip. While collapsed, tabs lose the active + /// style and all interactions, and the strip becomes the way a closed + /// bottom dock is opened again. #[allow(clippy::too_many_arguments)] fn render_tab( &self, @@ -578,10 +569,8 @@ impl TabGroupRenderer for SignedTabGroupSkin { if group.panels().is_empty() { return div().id("tab-panel"); } - // Closing the only panel of a bottom/right dock would leave an empty - // dock, which base refuses through the group. The skin removes the - // whole dock instead — the vendored dock's close took its split - // group away just the same. + // Closing the only panel of a bottom/right dock would leave an + // empty dock, which base refuses; the skin removes the dock instead. let dock_to_remove = (group.panels().len() <= 1) .then(|| self.is_dock_root_group(group, cx)) .flatten(); @@ -601,8 +590,8 @@ impl TabGroupRenderer for SignedTabGroupSkin { this.on_action({ let group = group.clone(); move |_: &ToggleZoom, window, cx| { - // The affordance decides the control, so a panel that - // offers none is not zoomed *in* by the keybinding + // The affordance decides the control, so a panel + // offering none is not zoomed *in* by the keybinding // either. Zooming out is never refused: a panel that // stopped offering the control while zoomed would // otherwise strand the user with no way back. @@ -671,12 +660,10 @@ impl TabGroupRenderer for SignedTabGroupSkin { let right_dock_button = self.dock_toggle_button(DockPlacement::Right, group, cx); let is_bottom_dock = bottom_dock_button.is_some(); - // macOS: the traffic lights overlay the window's top-left corner. Only - // the group whose tab bar actually sits under them must reserve the - // space: the left dock (sidebar) normally clears them, and when it is - // closed or absent it is the center's left-most, top-most tab group - // that is in the corner. A bottom or right dock is never there, and - // neither is the right panel of a center split. + // macOS: the traffic lights overlay the window's top-left corner. + // Only the group whose tab bar actually sits under them reserves the + // space — the center's left-most, top-most group when the left dock + // is closed or absent. let needs_traffic_light_padding = cfg!(target_os = "macos") && self.shared.area().upgrade().is_some_and(|area| { let area = area.read(cx); @@ -703,11 +690,10 @@ impl TabGroupRenderer for SignedTabGroupSkin { self.scroll_handle.scroll_to_item(visible_ix); } - // The tab strip lays out its scrollable content at content width, so - // the area after the last tab only spans `min_w_16` — the rest of the - // tab bar has no element at all. Cover that dead zone with a - // measured overlay so the whole non-interactive area can drag the - // window. Its span is [last tab's right edge, suffix's left edge]. + // The tab strip lays out at content width, so the area after the + // last tab has no element. Cover that dead zone (last tab's right + // edge to suffix's left edge) with a measured overlay so the whole + // non-interactive area can drag the window. let drag_overlay = match ( self.title_bar_bounds.get(), self.title_bar_strip_bounds.get(), diff --git a/crates/dock/src/tiles.rs b/crates/dock/src/tiles.rs index a8aaacd..1ac8d74 100644 --- a/crates/dock/src/tiles.rs +++ b/crates/dock/src/tiles.rs @@ -101,13 +101,11 @@ impl SignedTilesSkin { }) } - /// The trailing controls of a tile's title bar. - /// - /// A tile has no tab bar to hang a toolbar off, so this is where its zoom, - /// close and ellipsis menu live. The entries use click handlers rather - /// than the [`ToggleZoom`](crate::ToggleZoom) and - /// [`ClosePanel`](crate::ClosePanel) actions: those are dispatched to a - /// focused tab group, and a tile is not one. + /// The trailing controls of a tile's title bar: zoom, close and the + /// ellipsis menu. They use click handlers rather than the + /// [`ToggleZoom`](crate::ToggleZoom)/[`ClosePanel`](crate::ClosePanel) + /// actions, which are dispatched to a focused tab group — a tile is + /// not one. fn render_tile_controls( &self, tile: &TileContext, @@ -388,12 +386,9 @@ impl TilesRenderer for SignedTilesSkin { .size_full() } - /// The canvas scrollbar. - /// - /// It has to be an overlay rather than one of the frame's own children: - /// the frame is the scroll container and base appends the tiles after - /// whatever the frame carries, so a scrollbar placed there would paint and - /// hit-test underneath every tile. + /// The canvas scrollbar. It must be an overlay: the frame is the scroll + /// container and base appends the tiles after it, so a scrollbar placed + /// inside would paint and hit-test underneath every tile. fn render_overlay( &self, content: Size, diff --git a/crates/signed_core/src/filters.rs b/crates/signed_core/src/filters.rs index d11d929..00051eb 100644 --- a/crates/signed_core/src/filters.rs +++ b/crates/signed_core/src/filters.rs @@ -71,11 +71,10 @@ pub fn grasp_list(public_key: PublicKey) -> Filter { /// NIP-22 comments (kind `1111`) referencing any of the given root events /// (issues, patches, PRs). /// -/// Comments are not addressed to the repository — they carry no `a` tag with -/// the repo coordinate — so they must be fetched by their root reference -/// instead. NIP-22 defines the uppercase `E` tag as the root of the thread -/// (used by ngit) while some clients (including Signed itself) reference the -/// root with a lowercase `e` tag, so both are matched. +/// Comments carry no repository `a` tag, so they must be fetched by their +/// root reference. NIP-22 defines the uppercase `E` tag as the thread root +/// (used by ngit), but some clients (including Signed) use a lowercase `e` +/// tag, so both are matched. /// /// Returns two filters because `#E` and `#e` conditions would be ANDed if /// combined into one. diff --git a/crates/signed_git/src/lib.rs b/crates/signed_git/src/lib.rs index 33a2ab2..4413542 100644 --- a/crates/signed_git/src/lib.rs +++ b/crates/signed_git/src/lib.rs @@ -70,10 +70,9 @@ const SCAN_SKIPPED_DIRS: [&str; 1] = ["node_modules"]; /// Walk `root` recursively and collect the paths of git repositories /// (directories containing a `.git` entry) below it. /// -/// Hidden entries and symlinks are skipped, and directories that are -/// themselves repositories are not descended into (so nested repositories, -/// like submodule worktrees, are not reported). Results are canonicalized, -/// deduplicated and sorted by path. +/// Hidden entries and symlinks are skipped; repositories are not descended +/// into, so nested ones (e.g. submodule worktrees) are not reported. +/// Results are canonicalized, deduplicated and sorted. pub fn find_git_repos(root: &Path) -> Vec { let mut repos = Vec::new(); if !root.is_dir() { @@ -121,11 +120,9 @@ pub fn find_git_repos(root: &Path) -> Vec { /// Clone a repository into `path` from the first working URL in /// `clone_urls` (the announcement's `clone` tag), then fetch the /// `refs/nostr/*` PR refs like the cache clone does. The destination must -/// not exist yet; it is created by the clone. The first URL that works -/// wins; when none do, the error of the last failing URL is returned. +/// not exist yet. When no URL works, the last error is returned. /// -/// Unlike [`GitCache::ensure_clone`], the clone is not kept in any cache; -/// callers open it themselves if they need a [`gix::Repository`]. +/// Unlike [`GitCache::ensure_clone`], the clone is not kept in any cache. pub fn clone_repo(clone_urls: &[String], path: &Path) -> Result<()> { if path.exists() { bail!("destination {} already exists", path.display()); @@ -218,8 +215,8 @@ fn clone(url: &str, path: &Path) -> Result { /// `README.md` derived from `name`/`description`, and create the initial /// commit. Returns the initial commit id. /// -/// Uses the git CLI (like [`apply_patch`]) because it handles the plumbing -/// (index writes, ref updates, default branch selection) natively. +/// Uses the git CLI (like [`apply_patch`]), which handles index writes, +/// ref updates and default branch selection natively. pub fn init_repository(path: &Path, name: &str, description: &str) -> Result { std::fs::create_dir_all(path) .with_context(|| format!("failed to create {}", path.display()))?; @@ -371,11 +368,8 @@ fn git_in(dir: &Path, args: &[&str]) -> Result { } /// Map an untrusted repository id (or display name) to a safe single path -/// component. -/// -/// Replaces everything outside `[A-Za-z0-9._-]` with `_`, and rejects the -/// special components `.` and `..` so the id can't escape a directory it is -/// joined onto. +/// component: everything outside `[A-Za-z0-9._-]` becomes `_`, and the +/// special components `.` and `..` are rejected. pub fn sanitize_path_component(id: &str) -> String { let sanitized: String = id .chars() @@ -517,12 +511,9 @@ fn file_commit(commit: &gix::Commit<'_>, include_description: bool) -> Result` does for non-merge commits. -/// -/// Walks history from `HEAD` newest-first and returns the first commit whose -/// tree entry for `rel` differs from its first parent's; a merge that only -/// changed the file through its second parent is therefore not reported. -/// Returns `Ok(None)` if no commit touched the file (e.g. untracked files). +/// worktree), like `git log -1 -- `: the first commit, walking from +/// `HEAD` newest-first, whose tree entry for `rel` differs from its first +/// parent's. `Ok(None)` when no commit touched the file (e.g. untracked). pub fn last_commit(repo: &gix::Repository, rel: &Path) -> Result> { let rel = rel.to_path_buf(); Ok(last_commits(repo, std::slice::from_ref(&rel))? @@ -727,10 +718,8 @@ pub struct CommitDiff { } /// The changes of the commit `id` (short or full) in the repository at -/// `workdir`, compared against its first parent (the empty tree for the root -/// commit), like `git show`. Directory entries and submodules are skipped; -/// their contents are reported as individual file changes. Files are sorted -/// by path. +/// `workdir`, compared against its first parent (the empty tree for the +/// root commit), like `git show`. Files are sorted by path. pub fn worktree_commit_diff(workdir: &Path, id: &str) -> Result { commit_diff(&open_with_cache(workdir)?, id) } diff --git a/crates/signed_state/src/backend.rs b/crates/signed_state/src/backend.rs index d6d31d6..2884567 100644 --- a/crates/signed_state/src/backend.rs +++ b/crates/signed_state/src/backend.rs @@ -245,9 +245,8 @@ impl Backend { /// Decrypt the NIP-49 encrypted credential stored in the keyring with /// the given passphrase and resume the session. /// - /// The scrypt decryption runs off the UI thread. The returned task - /// yields the public key on success, or the failure reason (e.g. wrong - /// passphrase), so callers can render inline errors. + /// The scrypt decryption runs off the UI thread. The task yields the + /// public key, or the failure reason (e.g. wrong passphrase). pub fn restore_with_passphrase( &mut self, password: &str, @@ -286,9 +285,8 @@ impl Backend { /// passphrase (NIP-49) and persist it in the keyring, then publish the /// user's NIP-65 relay list, metadata and grasp list. /// - /// The heavy encryption runs off the UI thread. The returned task yields - /// the new public key on success, or the failure reason, so callers can - /// render progress and inline errors. + /// The encryption runs off the UI thread; the task yields the new + /// public key. pub fn create_identity( &mut self, name: &str, @@ -386,11 +384,8 @@ impl Backend { /// a push for a not-yet-existing repository while that authorization is /// pending (it expires after 30 minutes), like gitworkshop and ngit. /// - /// The git work (init, commit, push) runs on background threads. The - /// returned task yields the published announcement on success, so - /// callers can open the new repository right away. The announcement's - /// `relays` tag carries the grasp servers, which are also added to the - /// relay pool so the published events reach them. + /// The git work runs on background threads; the task yields the + /// published announcement. pub fn create_repository( &mut self, name: &str, @@ -435,8 +430,7 @@ impl Backend { let servers = grasp_servers.clone(); cx.spawn(async move |this, cx| { - // 1. Initialize the local clone (main branch + README + initial - // commit) on a background thread. + // Initialize the local clone (main branch + README + initial commit). let work = cx.background_spawn({ let path = path.clone(); let name = name.clone(); @@ -467,16 +461,14 @@ impl Backend { let commit_sha = Sha1Hash::from_str(&commit).map_err(|_| anyhow!("invalid initial commit id"))?; - // 2. Ensure the grasp servers are in the relay pool; the nostr - // client queues events until each relay is connected. + // The nostr client queues events until each relay is connected. this.update(cx, |this, cx| { let urls: Vec = servers.iter().map(ToString::to_string).collect(); this.add_relays(urls, cx); })?; - // 3. Publish the announcement, then the state event, to the - // grasp relays. The state event is the push authorization - // ("purgatory"), so it must be accepted before step 4. + // The state event is the push authorization ("purgatory"), so + // it must be accepted before the push below. let announcement = GitRepositoryAnnouncement { id: repo_id.clone(), name: Some(name.clone()), @@ -522,9 +514,8 @@ impl Backend { } }; - // 4. Push the initial commit to every grasp server. A server - // that fails to accept the push is logged, but the creation - // only fails when no server accepted it. + // Push to every grasp server; creation only fails when no + // server accepted it. let push = cx.background_spawn({ let path = path.clone(); let owner = owner.clone(); @@ -555,14 +546,8 @@ impl Backend { /// state to the grasp relays, then push every branch and tag to each /// grasp server. Also points `origin` at the first grasp server. /// - /// The events must reach the grasp servers *before* the push, like - /// [`Self::create_repository`]: GRASP servers hold the signed state - /// event in "purgatory" and only accept a push while that - /// authorization is pending. - /// - /// The git work (ref listing, push) runs on background threads. The - /// returned task yields the published announcement on success, so - /// callers can switch the repository into its NIP-34 mode. + /// Same ordering constraint as [`Self::create_repository`]: the state + /// event ("purgatory") must be accepted before the push. pub fn publish_local_repo( &mut self, path: PathBuf, @@ -586,9 +571,8 @@ impl Backend { return Task::ready(Err(anyhow!("Sign in to publish a repository"))); }; - // The repository identifier is derived from the name, like - // [`Self::create_repository`]: spaces become hyphens, other - // non-alphanumeric characters (except `/`) become hyphens. + // The repository identifier is derived from the name as in + // [`Self::create_repository`]. let repo_id = identifier_from_name(&name); if repo_id.is_empty() || repo_id.len() > 100 { @@ -607,8 +591,6 @@ impl Backend { let servers = grasp_servers.clone(); cx.spawn(async move |this, cx| { - // 1. Read the local repository's refs (branches, tags, HEAD) - // and its root commit on a background thread. let work = cx.background_spawn({ let path = path.clone(); async move { @@ -619,16 +601,14 @@ impl Backend { }); let (state, euc) = work.await?; - // 2. Ensure the grasp servers are in the relay pool; the nostr - // client queues events until each relay is connected. + // The nostr client queues events until each relay is connected. this.update(cx, |this, cx| { let urls: Vec = servers.iter().map(ToString::to_string).collect(); this.add_relays(urls, cx); })?; - // 3. Publish the announcement, then the state event, to the - // grasp relays. The state event is the push authorization - // ("purgatory"), so it must be accepted before step 4. + // The state event is the push authorization ("purgatory"), so + // it must be accepted before the push below. let announcement = GitRepositoryAnnouncement { id: repo_id.clone(), name: Some(name.clone()), @@ -672,10 +652,9 @@ impl Backend { } }; - // 4. Push every branch and tag to each grasp server. A server - // that fails to accept the push is logged, but the init only - // fails when no server accepted it. An empty repository - // (no refs yet) has nothing to push. + // Push every branch and tag to each grasp server; the init + // only fails when no server accepted it. An empty repository + // has nothing to push. if !refs.is_empty() { let push = cx.background_spawn({ let path = path.clone(); @@ -697,8 +676,8 @@ impl Backend { } } - // 5. Point `origin` at the first grasp server so later pushes - // have a target, like the create flow. + // Point `origin` at the first grasp server so later pushes + // have a target. if let Some(base) = servers.first().and_then(grasp_base_url) { let url = format!("{base}/{owner}/{repo_id}.git"); let path = path.clone(); @@ -732,15 +711,13 @@ impl Backend { let relays = announcement.relays.clone(); cx.spawn(async move |this, cx| { - // 1. Read the current refs of the local clone. let work = cx.background_spawn({ let path = path.clone(); async move { signed_git::worktree_ref_state(&path) } }); let state = work.await?; - // 2. Publish a fresh state event; grasp servers authorize a - // push by the state they have seen. + // Grasp servers authorize a push by the state they have seen. let refs = state.refs.clone(); let head = state.head.clone(); this.update(cx, |this, cx| { @@ -749,7 +726,6 @@ impl Backend { })? .await?; - // 3. Push every branch and tag to the announced grasp servers. if !refs.is_empty() { let push = cx.background_spawn({ let path = path.clone(); @@ -1111,9 +1087,8 @@ impl Backend { /// `filters`, plus a negentropy sync so issues, patches and PRs stored /// only on those relays are not missed. /// - /// Best-effort: failures are logged, not surfaced, because the bootstrap - /// relays already cover the repository. The relays stay in the pool, so - /// events the user publishes for this repository also reach them. + /// Best-effort: failures are logged, not surfaced. The relays stay in + /// the pool, so later publishes for this repository also reach them. pub fn connect_repo_relays( &mut self, relays: Vec, @@ -1221,10 +1196,9 @@ impl Backend { /// Sign, broadcast and locally store an event. Emits /// [`BackendEvent::Published`] on success so stores can refresh. /// - /// The returned task yields the outcome of this specific action, so - /// callers can show inline progress/errors instead of relying on - /// the global [`BackendEvent::Error`]. The task is owned by the caller; - /// dropping it cancels the publish. + /// The task yields the outcome of this specific action (for inline + /// progress/errors) and is owned by the caller; dropping it cancels + /// the publish. pub fn send( &mut self, builder: EventBuilder, diff --git a/crates/signed_state/src/lib.rs b/crates/signed_state/src/lib.rs index 927e859..9e22e89 100644 --- a/crates/signed_state/src/lib.rs +++ b/crates/signed_state/src/lib.rs @@ -34,7 +34,6 @@ pub fn init(db_path: impl AsRef, cx: &mut App) -> Entity { .install_default() .ok(); - // Initialize the nostr client and universal signer. let (client, signer) = cx.foreground_executor().block_on(async move { let path = db_path.as_ref().to_path_buf(); new_backend(path) @@ -42,24 +41,18 @@ pub fn init(db_path: impl AsRef, cx: &mut App) -> Entity { .expect("failed to initialize nostr backend") }); - // Initialize the backend and stores. let entity = cx.new(|cx| Backend::new(client, signer, cx)); Backend::set_global(entity.clone(), cx); - - // Initialize the profile store. ProfileStore::set_global(cx.new(ProfileStore::new), cx); - // Start the explore list from the local database before - // the first window opens, relay syncs continue in the background, - // so the list never waits for them. + // Seed the explore list from the local database; relay syncs continue + // in the background. RepoListStore::set_global(cx.new(|cx| RepoListStore::new(None, cx)), cx); - // The clone cache is only meaningful on native platforms, - // the wasm build registers an empty store so `GitStore::global` still works. + // The clone cache is native-only; wasm registers an empty store so + // `GitStore::global` still works. GitStore::set_global(PathBuf::new(), cx); - // Scan the default directories (Desktop, Documents) for local git - // repositories; the sidebar lists them next to the user's NIP-34 repos. LocalReposStore::set_global( cx.new(|cx| LocalReposStore::new(default_scan_paths(), cx)), cx, @@ -71,26 +64,13 @@ pub fn init(db_path: impl AsRef, cx: &mut App) -> Entity { /// Initialize the backend with an in-memory database on wasm. #[cfg(target_arch = "wasm32")] pub fn init(cx: &mut App) -> Entity { - // Initialize the nostr client and universal signer. let (client, signer) = new_backend().expect("failed to initialize nostr backend"); - // Initialize the backend and stores. let entity = cx.new(|cx| Backend::new(client, signer, cx)); Backend::set_global(entity.clone(), cx); - - // Initialize the profile store. ProfileStore::set_global(cx.new(ProfileStore::new), cx); - - // Start the explore list from the local database before - // the first window opens, relay syncs continue in the background, - // so the list never waits for them. RepoListStore::set_global(cx.new(|cx| RepoListStore::new(None, cx)), cx); - - // The clone cache is only meaningful on native platforms, - // the wasm build registers an empty store so `GitStore::global` still works. GitStore::set_global(PathBuf::new(), cx); - - // No filesystem scan on wasm: there are no local git repositories. LocalReposStore::set_global(cx.new(|cx| LocalReposStore::new(Vec::new(), cx)), cx); entity diff --git a/crates/signed_state/src/repo.rs b/crates/signed_state/src/repo.rs index 9f00170..8731422 100644 --- a/crates/signed_state/src/repo.rs +++ b/crates/signed_state/src/repo.rs @@ -586,15 +586,12 @@ impl RepoStore { /// (kind 1617) carrying the `git format-patch` output, which the PR /// references via an `e` tag (NIP-34). /// - /// The patch is published first and the PR is sent once the patch - /// event's id is known, so the two always arrive together. The proposed - /// commit is parsed from the patch's `From ` header; publishing - /// without one is refused, because the PR's `c` tag (and the patch's - /// `commit`/`r` tags) must carry a real commit id for other NIP-34 - /// clients to verify and apply the proposal. The PR's `clone` tag - /// carries the repository's announced mirror URLs (the commit may not be - /// pushed there yet; the linked patch is the source of truth until a - /// push backend exists). + /// The patch is published first so the PR can reference its id. The + /// proposed commit is parsed from the patch's `From ` header; + /// without one publishing is refused, because the PR's `c` tag must + /// carry a real commit id for other NIP-34 clients to verify and apply + /// the proposal. The `clone` tag carries the announced mirror URLs; the + /// linked patch is the source of truth until the commit is pushed there. pub fn open_pull_request( &mut self, subject: Option, @@ -783,10 +780,9 @@ impl RepoStore { /// the merged status. /// /// Only the repository author may merge. The clone is created on demand - /// from the announcement's clone URLs when the repository hasn't been - /// mirrored locally yet. Patch application runs on a background thread - /// (`git am`); failures (e.g. a patch that no longer applies) surface in - /// [`Self::last_error`] and no status is sent. + /// from the announcement's clone URLs when needed. Patch application + /// (`git am`) runs on a background thread; failures (e.g. a patch that + /// no longer applies) surface in [`Self::last_error`]. pub fn merge_pull_request(&mut self, root: &Event, cx: &mut Context) { self.last_error = None; @@ -876,12 +872,10 @@ fn patch_current_commit(patch: &str) -> Option<&str> { hex.split_whitespace().next().filter(|hex| hex.len() == 40) } -/// Build a NIP-22 kind-1111 comment using the SDK's [`CommentBuilder`]: -/// uppercase `E`/`K`/`P` tags scope the thread root, lowercase `e`/`k`/`p` -/// tags the direct parent (`parent`, or the root itself for a top-level -/// comment). An `a` tag with the repository coordinate is added so Signed's -/// own activity subscriptions also match the comment (it is not part of -/// NIP-22). +/// Build a NIP-22 kind-1111 comment: uppercase `E`/`K`/`P` tags scope the +/// thread root, lowercase `e`/`k`/`p` the direct parent (or the root for a +/// top-level comment). An `a` tag with the repository coordinate (not part +/// of NIP-22) is added so Signed's own activity subscriptions also match. fn comment_builder( root: &Event, parent: Option<&Event>, diff --git a/crates/signed_state/src/repo_list.rs b/crates/signed_state/src/repo_list.rs index 3d8d91f..480e679 100644 --- a/crates/signed_state/src/repo_list.rs +++ b/crates/signed_state/src/repo_list.rs @@ -22,8 +22,7 @@ impl Global for GlobalRepoListStore {} /// Counts of NIP-34 activity events per repository, used to rank the /// explore list by popularity. Each patch event is a pushed commit (or a -/// small commit series), which is the closest cross-repository proxy for -/// commit count available from event data alone. +/// small series), the closest proxy for commit count in the event data. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] pub struct RepoActivityCounts { /// Root `30611` issue events addressed to the repository. diff --git a/crates/workspace/src/views/repo_detail/browser.rs b/crates/workspace/src/views/repo_detail/browser.rs index 868f91d..fc839f8 100644 --- a/crates/workspace/src/views/repo_detail/browser.rs +++ b/crates/workspace/src/views/repo_detail/browser.rs @@ -39,12 +39,9 @@ pub(super) enum FileContent { /// A markdown document loaded into a persistent [`TextViewState`]. /// -/// The state is owned by the view rather than created per render (as the -/// stateless `text::markdown` helper does), so it survives branch switches -/// in the content pane. GPUI's keyed element state is dropped as soon as the -/// element is absent for a single frame, which would otherwise re-parse the -/// whole document on the main thread every time the pane switches between -/// the README, a file preview, and the loading spinner. +/// The state is owned by the view rather than created per render: GPUI +/// drops keyed element state after one absent frame, which would re-parse +/// the whole document on every pane switch (README / file / spinner). pub(super) struct MarkdownView { /// Source path; `None` means the repository README. pub(super) path: Option, @@ -53,11 +50,7 @@ pub(super) struct MarkdownView { /// A code file loaded into a persistent [`InputState`], rendered as a /// disabled (read-only) code editor with syntax highlighting, line numbers -/// and search. -/// -/// Same persistence rationale as [`MarkdownView`]: the state lives as long -/// as this view, so re-viewing the same file does not re-parse it, and -/// parsing happens on a background task inside the editor. +/// and search. Persistent for the same reason as [`MarkdownView`]. pub(super) struct CodeView { /// Source path, relative to the worktree root. pub(super) path: SharedString, @@ -230,9 +223,7 @@ impl RepoDetailView { /// Load `text` into the persistent markdown TextView state. /// /// The state is created empty and fed via `push_str`, which parses on a - /// background task: switching files never blocks the main thread, and - /// the state lives as long as this view, so re-viewing the same document - /// does not re-parse it. + /// background task, so switching files never blocks the main thread. pub(super) fn set_markdown( &mut self, path: Option, @@ -269,10 +260,8 @@ impl RepoDetailView { /// Load `text` into the persistent code editor state for `path`. /// /// The state is created in code editor mode so the Input renders it as - /// a syntax-highlighted, read-only editor. Like [`set_markdown`], the - /// state lives as long as this view, so re-viewing the same file does - /// not re-parse it; the tree-sitter parse runs on a background task - /// inside the editor instead of blocking the main thread. + /// a syntax-highlighted, read-only editor; the tree-sitter parse runs + /// on a background task like [`set_markdown`]'s. pub(super) fn set_code( &mut self, path: SharedString, diff --git a/crates/workspace/src/views/repo_detail/helpers.rs b/crates/workspace/src/views/repo_detail/helpers.rs index 43b4430..f69167f 100644 --- a/crates/workspace/src/views/repo_detail/helpers.rs +++ b/crates/workspace/src/views/repo_detail/helpers.rs @@ -276,11 +276,8 @@ pub(super) fn status_badge(status: RepoStatus, cx: &App) -> AnyElement { /// A split dropdown button built on `gpui_base::Popover`: an action element /// with a separate caret trigger that opens a [`PopupMenu`]. /// -/// The action and the caret are ordinary elements supplied by the caller, so -/// the look — icons, borders, hover states, sizes — stays fully in the -/// application. The component only owns the popover wiring: opening on caret -/// click, Escape/outside dismissal, focus movement into the menu, and the -/// menu entity's lifecycle. +/// The action and the caret are caller-supplied elements, so the look stays +/// in the application; this component only owns the popover wiring. #[derive(IntoElement)] pub(super) struct BaseDropdownButton { id: ElementId, @@ -493,11 +490,10 @@ impl ShareTargets { } } -/// One row of the share menu: a small title on top of the compact label, -/// with a copy button that flips to a check while the value is on the -/// clipboard. Clicking the row text copies and dismisses the menu; the copy -/// button stops propagation, so the menu stays open for further copies. -/// Both copy `copy`, never the truncated label. +/// One row of the share menu: a small title above the compact label, with +/// a copy button that flips to a check while the value is on the clipboard. +/// Clicking the row copies and dismisses the menu; the copy button stops +/// propagation so the menu stays open. Both copy `copy`, never the label. pub(super) fn share_menu_row( id: &'static str, title: &'static str, diff --git a/crates/workspace/src/views/repo_detail/issues.rs b/crates/workspace/src/views/repo_detail/issues.rs index 8e7d8c9..9a715f0 100644 --- a/crates/workspace/src/views/repo_detail/issues.rs +++ b/crates/workspace/src/views/repo_detail/issues.rs @@ -26,10 +26,8 @@ use super::helpers::{placeholder, status_badge}; use super::issue_detail::IssueDetailView; use crate::image_cache::{MAX_IMAGES, image_cache}; -/// Height of one issue row in the virtual list: 8px vertical padding -/// (`py_2`) on top and bottom, a 32px title line (`h_8`) and a 24px meta -/// line (`h_6`), plus the 1px bottom border; the row totals 73px. The -/// status chip (`size_7`, 28px) is shorter than the content. +/// Height of one issue row in the virtual list: `py_2` padding, a 32px +/// title line (`h_8`), a 24px meta line (`h_6`) and the 1px bottom border. const ISSUE_ROW_HEIGHT: f32 = 73.; /// Status filter of the issues list, chosen via the header's filter buttons. @@ -39,8 +37,8 @@ enum IssueFilter { All, /// Issues whose resolved status is [`RepoStatus::Open`]. Open, - /// Issues whose resolved status is - /// [`RepoStatus::Closed`] or [`RepoStatus::Applied`] (both are "done" states). + /// Issues whose resolved status is [`RepoStatus::Closed`] or + /// [`RepoStatus::Applied`] (both are "done" states). Closed, } diff --git a/crates/workspace/src/views/repo_detail/mod.rs b/crates/workspace/src/views/repo_detail/mod.rs index d8558d0..531e44f 100644 --- a/crates/workspace/src/views/repo_detail/mod.rs +++ b/crates/workspace/src/views/repo_detail/mod.rs @@ -308,9 +308,7 @@ impl RepoDetailView { /// (not yet published) repository is opened straight from disk. An /// announced repository's local clone (if any) is loaded first without /// touching the network, so an unreachable server can't block the - /// panel; a background fetch then refreshes the refs and commit list - /// (a fetch never changes the checked-out files, so the tree and - /// previews are left alone). + /// panel; a background fetch then refreshes the refs and commit list. fn load_repo(&mut self, window: &mut Window, cx: &mut Context) { self.loading = true; self.error = None; @@ -505,9 +503,7 @@ impl RepoDetailView { } /// Clone the repository into a folder chosen by the user (outside the - /// cache), then open the new clone in the system file manager. Like - /// ngit's clone, this resolves the announcement's `clone` URLs and - /// clones from the first working git server. + /// cache), then open the new clone in the system file manager. fn clone_to_folder(&mut self, window: &mut Window, cx: &mut Context) { if self.cloning { return; @@ -722,11 +718,8 @@ impl RepoDetailView { /// Walk history once for every queued path on a background task, and /// cache the latest commit touching each of them in [`Self::commits`] - /// (for the file header in the content column). - /// - /// Batching shares one walk (and its object decodes) across all paths - /// queued while the previous walk was in flight, instead of walking the - /// full history per file. + /// (for the file header in the content column). Batching shares one + /// walk across all paths queued while the previous walk was in flight. fn load_commits(&mut self, cx: &mut Context) { if self.pending_commits.is_empty() || self.loading_commits { return; @@ -1029,8 +1022,7 @@ impl RepoDetailView { /// Trigger body for the branch/tag selectors: the kind icon, the /// selection (or placeholder) and the caret. `Combobox` replaces its - /// default trigger entirely, which is the only way to show an icon - /// inside the trigger label. + /// default trigger entirely, the only way to show an icon inside it. fn render_ref_trigger( ctx: &ComboboxTriggerContext>, icon: CustomIconName, @@ -1923,9 +1915,7 @@ impl Render for RepoDetailView { } /// Read the worktree state of `repo` (no network): entries, README, refs -/// and HEAD commit. The tree is built off the main thread; the seeds are -/// plain owned strings and convert to `TreeItem`s (which hold `Rc` state) -/// on the main thread. +/// and HEAD commit. fn load_repo_data(repo: &Repository) -> Result { let entries = signed_git::worktree_entries(repo)?; let tree = build_tree_items(&entries); diff --git a/crates/workspace/src/views/repo_detail/pull_request_detail.rs b/crates/workspace/src/views/repo_detail/pull_request_detail.rs index 0cb57f2..896e39a 100644 --- a/crates/workspace/src/views/repo_detail/pull_request_detail.rs +++ b/crates/workspace/src/views/repo_detail/pull_request_detail.rs @@ -146,9 +146,8 @@ impl PullRequestDetailView { /// and commit list on a background task and populate the tree. /// /// The changes come from the PR's patch set (NIP-34 `e`-linked patch - /// events) when present; otherwise they live in the git repository - /// (`c`, `clone` and `merge-base` tags, per NIP-34), so the clone is - /// fetched and the `merge-base..tip` range is diffed. + /// events) when present; otherwise from the git repository (`c`, + /// `clone` and `merge-base` tags), diffing the `merge-base..tip` range. fn load(&mut self, window: &mut Window, cx: &mut Context) { self.loading = true; self.error = None; diff --git a/crates/workspace/src/views/repo_detail/pull_requests.rs b/crates/workspace/src/views/repo_detail/pull_requests.rs index acff79b..8c5fa33 100644 --- a/crates/workspace/src/views/repo_detail/pull_requests.rs +++ b/crates/workspace/src/views/repo_detail/pull_requests.rs @@ -26,11 +26,8 @@ use super::helpers::{placeholder, status_badge}; use super::pull_request_detail::PullRequestDetailView; use crate::image_cache::{MAX_IMAGES, image_cache}; -/// Height of one pull request row in the virtual list: same layout as an -/// issue row (8px vertical padding (`py_2`) on top and bottom, a 32px title -/// line (`h_8`) and a 24px meta line (`h_6`), plus the 1px bottom border), -/// so the row totals 73px. The status badge (`size_7`, 28px) is shorter -/// than the content. +/// Height of one pull request row in the virtual list; same layout as an +/// issue row. const PR_ROW_HEIGHT: f32 = 73.; /// Status filter of the pull request list, chosen via the header's filter @@ -79,9 +76,8 @@ pub struct PullRequestsView { /// pull request count); rebuilt on change. pr_len: usize, /// Indices into the store's `pull_requests` matching [`Self::filter`] - /// (root PR events only; updates are revisions of the root and are not - /// listed separately), rebuilt every render; the virtual list renders - /// this slice. + /// (root PR events only; updates are revisions of the root), rebuilt + /// every render; the virtual list renders this slice. visible_prs: Vec, /// Virtual list state of the pull requests list. scroll_handle: VirtualListScrollHandle, diff --git a/crates/workspace/src/views/repo_list.rs b/crates/workspace/src/views/repo_list.rs index 5e3dc44..3d2beff 100644 --- a/crates/workspace/src/views/repo_list.rs +++ b/crates/workspace/src/views/repo_list.rs @@ -97,9 +97,7 @@ pub struct RepoListView { /// Number of rows [`Self::item_sizes`] was built for (the filtered repo count). repo_len: usize, /// Indices into the store's `announcements` matching [`Self::filter`], - /// in display order; rebuilt when the store changes, the filter is - /// switched, or the search text changes. The virtual list renders this - /// slice. + /// in display order; the virtual list renders this slice. visible: Vec, /// Search box filtering repositories by name. search: Entity, @@ -153,10 +151,7 @@ impl RepoListView { } /// Rebuild [`Self::visible`] and [`Self::item_sizes`] from the current - /// store contents, [`Self::filter`] and the search query. Called when - /// the view is created, when the store changes, when the filter is - /// switched, and on every search keystroke, so the list is ready before - /// the next render. + /// store contents, [`Self::filter`] and the search query. fn rebuild_rows(&mut self, cx: &mut Context) { let filter = self.filter; let query = self.search.read(cx).value(); diff --git a/crates/workspace/src/views/sidebar/mod.rs b/crates/workspace/src/views/sidebar/mod.rs index 98886a5..5e5929d 100644 --- a/crates/workspace/src/views/sidebar/mod.rs +++ b/crates/workspace/src/views/sidebar/mod.rs @@ -417,9 +417,8 @@ impl SidebarPanel { ) } - /// Sign-in placeholder shown while logged out: the banner artwork fills the - /// panel behind a scrim that ends in a solid black band, keeping the CTA - /// buttons readable on a clean dark surface in both themes. + /// Sign-in placeholder shown while logged out: banner artwork behind a + /// scrim so the CTA buttons stay readable in both themes. fn render_sign_in(&self, window: &mut Window, cx: &mut Context) -> Div { v_flex() .size_full() diff --git a/desktop/src/main.rs b/desktop/src/main.rs index 930230c..fa2bce4 100644 --- a/desktop/src/main.rs +++ b/desktop/src/main.rs @@ -7,17 +7,13 @@ use gpui_component::{Theme, ThemeRegistry, theme}; use gpui_platform::application; fn main() { - // Initialize logging tracing_subscriber::fmt::init(); application() .with_assets(Assets) .with_http_client(Arc::new(reqwest_client::ReqwestClient::new())) .run(move |cx| { - // Initialize components gpui_component::init(cx); - - // Initialize theme theme::init(cx); // Register the built-in "Signed" theme (light + dark variants) @@ -49,10 +45,9 @@ fn main() { tracing::warn!("Signed Dark theme is missing from the registry"); } - // Sync the theme with the system appearance Theme::sync_system_appearance(None, cx); - // Initialize backend and stores (connects relays, restores session) + // Connects relays and restores the session. std::fs::create_dir_all(paths::nostr_dir()).ok(); signed_state::init(paths::nostr_dir(), cx); @@ -60,15 +55,9 @@ fn main() { std::fs::create_dir_all(paths::repos_dir()).ok(); signed_state::GitStore::set_global(paths::repos_dir().clone(), cx); - // Set app identity cx.set_app_identity("su.reya.signed", "Signed"); - // Set up the window options let bounds = Bounds::centered(None, size(px(1120.0), px(750.0)), cx); - - // The dock's tab bar acts as the window title bar: the app owns - // title-bar dragging (via `start_window_move` on the tab bar), so - // AppKit must not treat the top strip as a native drag region. let opts = WindowOptions { window_background: WindowBackgroundAppearance::Opaque, window_decorations: Some(WindowDecorations::Client), @@ -78,7 +67,7 @@ fn main() { app_id: Some("Signed".to_owned()), titlebar: Some(TitlebarOptions { title: Some(SharedString::new_static("Signed")), - // AppKit's traffic-light buttons are 14 pt tall; offset them so their vertical center matches the tab bar. + // Center the 14pt traffic-light buttons on the tab bar. traffic_light_position: Some(point( px(9.0), px(TAB_BAR_HEIGHT / px(2.) - 14. / 2.), @@ -94,7 +83,6 @@ fn main() { }) .detach(); - // Bring the app to the foreground cx.activate(true); }); } diff --git a/docs/TODO.md b/docs/TODO.md index b5bfff4..bfeefcc 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -2,8 +2,8 @@ ## Local repository scan -- [ ] Allow the user to configure which directories are scanned for local git repositories (currently fixed to the Desktop and Documents folders). +- [ ] Make the scanned directories configurable (currently fixed to Desktop and Documents). ## Create repository dialog -- [ ] Persist the user's preferred local repository folder (the one picked in the create-repository dialog, defaulting to Desktop) and use it as the default next time the dialog opens. +- [ ] Remember the folder picked in the create-repository dialog and default to it next time (currently defaults to Desktop).