From 15c2122f3846ebc203ce1c79d66c2358c785d7b4 Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Fri, 4 Sep 2026 17:23:10 +0700 Subject: [PATCH] clean up --- Cargo.lock | 1 - crates/paths/src/lib.rs | 4 +++ crates/signed_core/Cargo.toml | 1 - crates/signed_core/src/model.rs | 34 +++++++++---------- crates/signed_state/src/repo.rs | 2 +- crates/signed_ui/src/copy_row.rs | 5 ++- .../workspace/src/views/repo_detail/about.rs | 17 +++++++--- .../src/views/repo_detail/browser.rs | 2 +- crates/workspace/src/views/repo_detail/mod.rs | 8 +++-- .../src/views/repo_detail/new_pull_request.rs | 3 +- crates/workspace/src/views/repo_list.rs | 11 +++--- crates/workspace/src/views/sidebar/mod.rs | 3 +- docs/PR_FLOW.md | 18 +++++----- 13 files changed, 63 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ae229c2..dfd3028 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7900,7 +7900,6 @@ dependencies = [ name = "signed_core" version = "1.0.0" dependencies = [ - "gpui", "nostr", ] diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs index 3e0b0e8..7668e60 100644 --- a/crates/paths/src/lib.rs +++ b/crates/paths/src/lib.rs @@ -2,10 +2,12 @@ use std::path::PathBuf; use std::sync::OnceLock; /// The application name. +/// /// It derives the platform-specific data, config and cache directory paths. pub const APP_NAME: &str = "Signed"; /// Lowercased form of [`APP_NAME`]. +/// /// Used in XDG-style paths on Linux and FreeBSD, and the macOS `~/.config` fallback. pub const APP_NAME_LOWERCASE: &str = "signed"; @@ -27,12 +29,14 @@ pub fn home_dir() -> PathBuf { } /// Returns the current user's Desktop folder. +/// /// Falls back to the home directory or an empty path when it cannot be determined. pub fn desktop_dir() -> PathBuf { dirs::desktop_dir().unwrap_or_else(|| dirs::home_dir().unwrap_or_default()) } /// Returns the current user's Documents folder. +/// /// Falls back to the home directory or an empty path when it cannot be determined. pub fn documents_dir() -> PathBuf { dirs::document_dir().unwrap_or_else(|| dirs::home_dir().unwrap_or_default()) diff --git a/crates/signed_core/Cargo.toml b/crates/signed_core/Cargo.toml index bd77e36..5b1e5ca 100644 --- a/crates/signed_core/Cargo.toml +++ b/crates/signed_core/Cargo.toml @@ -5,5 +5,4 @@ edition.workspace = true publish.workspace = true [dependencies] -gpui.workspace = true nostr.workspace = true diff --git a/crates/signed_core/src/model.rs b/crates/signed_core/src/model.rs index 963202c..d977d7e 100644 --- a/crates/signed_core/src/model.rs +++ b/crates/signed_core/src/model.rs @@ -1,6 +1,5 @@ use std::collections::HashSet; -use gpui::SharedString; use nostr::prelude::*; use crate::RepoAddr; @@ -16,8 +15,8 @@ pub struct Announcement { pub owner: PublicKey, /// When the announcement was published, used for latest-wins resolution. pub created_at: Timestamp, - pub name: Option, - pub description: Option, + pub name: Option, + pub description: Option, /// Webpage URLs for browsing. pub web: Vec, /// URLs for `git clone`. @@ -62,17 +61,17 @@ impl Upstream { } /// Text for display. - pub fn display(&self) -> SharedString { + pub fn display(&self) -> String { match &self.addr { - Some(addr) => SharedString::from(addr.to_string()), - None => SharedString::from(self.raw.clone()), + Some(addr) => addr.to_string(), + None => self.raw.clone(), } } } /// Subject of a NIP-34 issue or pull request event. /// Taken from the `subject` tag, else the first non-empty line of the content. -pub fn activity_subject(event: &Event) -> SharedString { +pub fn activity_subject(event: &Event) -> String { let subject = event .tags .iter() @@ -82,16 +81,15 @@ pub fn activity_subject(event: &Event) -> SharedString { }); subject - .map(SharedString::from) .or_else(|| { event .content .lines() .map(str::trim) .find(|line| !line.is_empty()) - .map(SharedString::from) + .map(|value| value.to_string()) }) - .unwrap_or(SharedString::from("Untitled")) + .unwrap_or("Untitled".to_string()) } /// The patch set of a pull request. @@ -219,8 +217,8 @@ impl Announcement { let mut hashtags: Vec = Vec::new(); hashtags.extend(event.tags.hashtags().map(|t| t.to_string())); - let mut name: Option = None; - let mut description: Option = None; + let mut name: Option = None; + let mut description: Option = None; let mut web: Vec = Vec::new(); let mut clone: Vec = Vec::new(); let mut relays: Vec = Vec::new(); @@ -230,8 +228,8 @@ impl Announcement { for tag in event.tags.iter() { match Nip34Tag::parse(tag.as_slice()) { - Ok(Nip34Tag::Name(value)) => name = Some(value.into()), - Ok(Nip34Tag::Description(value)) => description = Some(value.into()), + Ok(Nip34Tag::Name(value)) => name = Some(value), + Ok(Nip34Tag::Description(value)) => description = Some(value), Ok(Nip34Tag::Web(urls)) => web.extend(urls), Ok(Nip34Tag::Clone(urls)) => clone.extend(urls), Ok(Nip34Tag::Relays(urls)) => relays.extend(urls), @@ -288,10 +286,10 @@ impl Announcement { } /// The description of the repository, or a default if none is provided. - pub fn description(&self) -> SharedString { + pub fn description(&self) -> String { self.description .clone() - .unwrap_or(SharedString::from("No description")) + .unwrap_or("No description".to_string()) } /// The effective maintainers of this repository, @@ -307,11 +305,11 @@ impl Announcement { } /// The `git clone` URLs for this repository, deduplicated. - pub fn clone_urls(&self) -> Vec { + pub fn clone_urls(&self) -> Vec { let mut seen = HashSet::new(); self.clone .iter() - .map(|url| SharedString::from(format!("git clone {url}"))) + .map(|url| format!("git clone {url}")) .filter(|command| seen.insert(command.clone())) .collect() } diff --git a/crates/signed_state/src/repo.rs b/crates/signed_state/src/repo.rs index 7778010..47c0106 100644 --- a/crates/signed_state/src/repo.rs +++ b/crates/signed_state/src/repo.rs @@ -153,7 +153,7 @@ impl RepoStore { self.announcement .as_ref() .map_or(SharedString::default(), |a| { - a.name.clone().unwrap_or(SharedString::from("Unknown")) + SharedString::from(a.name.as_deref().unwrap_or("Unknown")) }) } diff --git a/crates/signed_ui/src/copy_row.rs b/crates/signed_ui/src/copy_row.rs index 4ed20cb..b94f30b 100644 --- a/crates/signed_ui/src/copy_row.rs +++ b/crates/signed_ui/src/copy_row.rs @@ -5,10 +5,13 @@ use gpui_component::menu::PopupMenuItem; use gpui_component::{ActiveTheme, StyledExt, h_flex}; /// A muted command row with a copy button. -pub fn copy_row(copy_id: E, command: &SharedString, cx: &App) -> Div +pub fn copy_row(copy_id: E, command: T, cx: &App) -> Div where E: Into, + T: Into, { + let command = command.into(); + h_flex() .h_8() .w_full() diff --git a/crates/workspace/src/views/repo_detail/about.rs b/crates/workspace/src/views/repo_detail/about.rs index da71285..d9e7568 100644 --- a/crates/workspace/src/views/repo_detail/about.rs +++ b/crates/workspace/src/views/repo_detail/about.rs @@ -30,8 +30,9 @@ fn announcement_rows(announcement: &Announcement, cx: &App) -> AnyElement { text( announcement .name - .clone() - .unwrap_or_else(|| SharedString::from("—")), + .as_deref() + .map(SharedString::from) + .unwrap_or_else(|| SharedString::from("-")), ), cx, )); @@ -41,8 +42,9 @@ fn announcement_rows(announcement: &Announcement, cx: &App) -> AnyElement { text( announcement .description - .clone() - .unwrap_or_else(|| SharedString::from("—")), + .as_deref() + .map(SharedString::from) + .unwrap_or_else(|| SharedString::from("-")), ), cx, )); @@ -131,7 +133,12 @@ fn row(label: &'static str, value: AnyElement, cx: &App) -> AnyElement { } /// Plain text value, wrapping within the dialog. -fn text(value: SharedString) -> AnyElement { +fn text(value: T) -> AnyElement +where + T: Into, +{ + let value = value.into(); + div() .text_sm() .w_full() diff --git a/crates/workspace/src/views/repo_detail/browser.rs b/crates/workspace/src/views/repo_detail/browser.rs index 2d44e1a..389aeae 100644 --- a/crates/workspace/src/views/repo_detail/browser.rs +++ b/crates/workspace/src/views/repo_detail/browser.rs @@ -143,7 +143,7 @@ impl RepoDetailView { self.code_element(path.as_ref(), cx) } } - Some(FileContent::Binary) => placeholder("Binary file — preview not supported", cx), + Some(FileContent::Binary) => placeholder("Binary file - preview not supported", cx), Some(FileContent::TooLarge) => placeholder("File is too large to preview", cx), Some(FileContent::Failed(message)) => placeholder(message, cx), None => preview_spinner(), diff --git a/crates/workspace/src/views/repo_detail/mod.rs b/crates/workspace/src/views/repo_detail/mod.rs index f0b8109..f83636f 100644 --- a/crates/workspace/src/views/repo_detail/mod.rs +++ b/crates/workspace/src/views/repo_detail/mod.rs @@ -1342,7 +1342,8 @@ impl RepoDetailView { .map(|announcement| { announcement .name - .clone() + .as_deref() + .map(SharedString::from) .unwrap_or_else(|| SharedString::from(announcement.id.clone())) }) .unwrap_or_default() @@ -2359,13 +2360,14 @@ fn fork_row(announcement: &Announcement, cx: &mut Context) -> Op .find(|a| a.addr() == *addr) .map(|a| { a.name - .clone() + .as_deref() + .map(SharedString::from) .unwrap_or_else(|| SharedString::from(a.id.clone())) }) .unwrap_or_else(|| SharedString::from(addr.identifier.clone())); (SharedString::from(format!("Forked from {name}")), true) } - None => (upstream.display(), false), + None => (SharedString::from(upstream.display().as_str()), false), }; let row = h_flex() diff --git a/crates/workspace/src/views/repo_detail/new_pull_request.rs b/crates/workspace/src/views/repo_detail/new_pull_request.rs index d5d9828..6512ac4 100644 --- a/crates/workspace/src/views/repo_detail/new_pull_request.rs +++ b/crates/workspace/src/views/repo_detail/new_pull_request.rs @@ -140,7 +140,8 @@ fn fork_candidates<'a>( fn fork_display_name(announcement: &Announcement) -> SharedString { announcement .name - .clone() + .as_deref() + .map(SharedString::from) .unwrap_or_else(|| SharedString::from(announcement.id.clone())) } diff --git a/crates/workspace/src/views/repo_list.rs b/crates/workspace/src/views/repo_list.rs index 6876c46..126669a 100644 --- a/crates/workspace/src/views/repo_list.rs +++ b/crates/workspace/src/views/repo_list.rs @@ -187,12 +187,14 @@ impl RepoListView { let name = announcement .name - .clone() - .unwrap_or_else(|| SharedString::from(announcement.id.clone())); + .as_deref() + .map(SharedString::from) + .unwrap_or(SharedString::from(announcement.id.clone())); let description = announcement .description - .clone() + .as_deref() + .map(SharedString::from) .unwrap_or(SharedString::from("No description")); let activity = last_activity @@ -213,7 +215,8 @@ impl RepoListView { .find(|a| a.addr() == *addr) .map(|a| { a.name - .clone() + .as_deref() + .map(SharedString::from) .unwrap_or_else(|| SharedString::from(a.id.clone())) }) .unwrap_or_else(|| SharedString::from(addr.identifier.clone())); diff --git a/crates/workspace/src/views/sidebar/mod.rs b/crates/workspace/src/views/sidebar/mod.rs index caa8a15..18e6522 100644 --- a/crates/workspace/src/views/sidebar/mod.rs +++ b/crates/workspace/src/views/sidebar/mod.rs @@ -347,7 +347,8 @@ impl SidebarPanel { ) -> impl IntoElement { let name = announcement .name - .clone() + .as_deref() + .map(SharedString::from) .unwrap_or_else(|| SharedString::from(announcement.id.clone())); let avatar = PixelAvatar::new(format!("{}:{}", announcement.owner, announcement.id)); diff --git a/docs/PR_FLOW.md b/docs/PR_FLOW.md index c1066b8..10e8e0f 100644 --- a/docs/PR_FLOW.md +++ b/docs/PR_FLOW.md @@ -55,19 +55,19 @@ Key points of the write side: branches; all git ops run in that folder. Checkouts of the target repo are remembered (folder pick + app clones) and matched implicitly (origin URL or EUC against the announcement), so the panel prefills the - freshest one — no folder dialog for the common case. + freshest one - no folder dialog for the common case. - *Announced fork*: the fork's heads are fetched into the target repo's GitCache mirror under `refs/fork///*` (private namespace; the browser never sees them). "Merge Into" lists the mirror's `refs/remotes/origin/*`, "Pull From" the imported fork - branches, and every git op — merge-base, range diff/commits, - format-patch, tip push — runs in the mirror, which holds both + branches, and every git op - merge-base, range diff/commits, + format-patch, tip push - runs in the mirror, which holds both histories. Fork candidates are announcements related to the target by `u` tag or shared EUC, own forks first, without `clone` URLs excluded. - **GRASP-06 hosting**: the tip is pushed under `refs/nostr/` - (nak's convention) to the *author's* grasp servers first — + (nak's convention) to the *author's* grasp servers first - `https:///prs//.git`, resolved from the - author's kind-10317 grasp list, falling back to the settings defaults — + author's kind-10317 grasp list, falling back to the settings defaults - then to the base repository's announced grasp servers. The `clone` tag lists those `/prs/` URLs first, then the announced clone URLs (fixed before signing; dead URLs are inert, the patches stay the source of @@ -77,8 +77,8 @@ Key points of the write side: grows past NIP-34's 60 KB guidance; the PR's `c` tag carries the *last* commit of the series (the tip), and each part carries its own `commit`/`r` tags. -- **Push before publish**: failure is non-fatal — the patch events remain - the source of truth — and surfaces as a `last_warning` banner. +- **Push before publish**: failure is non-fatal - the patch events remain + the source of truth - and surfaces as a `last_warning` banner. - **1619 updates are paste-only today** (no repo path holds the new tip's objects), so updates are not pushed; hosting them is deferred until the update dialog gains a local-checkout source. @@ -120,7 +120,7 @@ thread: current branch vs its base (announced HEAD, else `main`, else the first branch), commits ahead, dirty worktrees excluded. A banner in the repository panel then offers a prefilled New PR panel for the first branch that is ahead with **no open PR by you** proposing it (`branch-name` tag, -falling back to the `c` tip tag) — NIP-34-native dedupe, refreshed +falling back to the `c` tip tag) - NIP-34-native dedupe, refreshed periodically and whenever the checkouts/announcements change. The panel never submits anything on its own; suggestions only navigate and prefill. @@ -165,7 +165,7 @@ Reader rules that keep the flow consistent: - **Status**: only status events by the root author or a repository maintainer count; the newest wins, `Open` is the default. -- **Tip**: only kind-1619 updates by the PR author move the tip — a +- **Tip**: only kind-1619 updates by the PR author move the tip - a stranger's update is ignored. - **Diff**: the patch set is preferred (NIP-34 `e`-linked chain); PRs from other clients without patch events fall back to diffing