cob: improve Comment generics
`Infallible` is a more appropriate type in comparsion to `()` for comments that do not require a `CodeLocation`. That is because if the type for `location` is `Option<()>`, this means that `Some(())` can be constructed, however, we never intend to construct that variant. On the other hand, `Infallible` can never be constructed, and so, only `None` can be used. This requires updates to some functions to use the generic `T` and also handle the different kinds of `Comment`s -- `Infallible` and `CodeLocation`. X-Co-Authored-By: Fintan Halpenny <fintan.halpenny@gmail.com>
This commit is contained in:
parent
48843434c7
commit
1f36879aa2
|
|
@ -5,9 +5,9 @@ use crate::terminal as term;
|
||||||
use crate::terminal::format::Author;
|
use crate::terminal::format::Author;
|
||||||
|
|
||||||
/// Return a comment header as a [`term::Element`].
|
/// Return a comment header as a [`term::Element`].
|
||||||
pub fn header(
|
pub fn header<T>(
|
||||||
id: &CommentId,
|
id: &CommentId,
|
||||||
comment: &Comment,
|
comment: &Comment<T>,
|
||||||
profile: &Profile,
|
profile: &Profile,
|
||||||
) -> term::hstack::HStack<'static> {
|
) -> term::hstack::HStack<'static> {
|
||||||
let author = comment.author();
|
let author = comment.author();
|
||||||
|
|
@ -27,7 +27,7 @@ pub fn header(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a full comment widget as a [`term::Element`].
|
/// Return a full comment widget as a [`term::Element`].
|
||||||
pub fn widget<'a>(id: &CommentId, comment: &Comment, profile: &Profile) -> term::VStack<'a> {
|
pub fn widget<'a, T>(id: &CommentId, comment: &Comment<T>, profile: &Profile) -> term::VStack<'a> {
|
||||||
term::vstack::bordered(header(id, comment, profile))
|
term::vstack::bordered(header(id, comment, profile))
|
||||||
.child(term::textarea(comment.body()).wrap(60))
|
.child(term::textarea(comment.body()).wrap(60))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ pub(crate) fn issue(id: IssueId, issue: Issue, aliases: &impl AliasStore) -> Val
|
||||||
"title": issue.title(),
|
"title": issue.title(),
|
||||||
"state": issue.state(),
|
"state": issue.state(),
|
||||||
"assignees": issue.assignees().collect::<Vec<_>>(),
|
"assignees": issue.assignees().collect::<Vec<_>>(),
|
||||||
"discussion": issue.comments().map(|(id, c)| comment(id, c, aliases)).collect::<Vec<_>>(),
|
"discussion": issue.comments().map(|(id, c)| issue_comment(id, c, aliases)).collect::<Vec<_>>(),
|
||||||
"labels": issue.labels().collect::<Vec<_>>(),
|
"labels": issue.labels().collect::<Vec<_>>(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -132,7 +132,7 @@ pub(crate) fn patch(
|
||||||
"base": rev.base(),
|
"base": rev.base(),
|
||||||
"oid": rev.head(),
|
"oid": rev.head(),
|
||||||
"refs": get_refs(repo, patch.author().id(), &rev.head()).unwrap_or_default(),
|
"refs": get_refs(repo, patch.author().id(), &rev.head()).unwrap_or_default(),
|
||||||
"discussions": rev.discussion().comments().map(|(id, c)| comment(id, c, aliases)).collect::<Vec<_>>(),
|
"discussions": rev.discussion().comments().map(|(id, c)| patch_comment(id, c, aliases)).collect::<Vec<_>>(),
|
||||||
"timestamp": rev.timestamp().as_secs(),
|
"timestamp": rev.timestamp().as_secs(),
|
||||||
"reviews": rev.reviews().map(|(nid, r)| review(nid, r, aliases)).collect::<Vec<_>>(),
|
"reviews": rev.reviews().map(|(nid, r)| review(nid, r, aliases)).collect::<Vec<_>>(),
|
||||||
})
|
})
|
||||||
|
|
@ -172,8 +172,8 @@ fn review(nid: &NodeId, review: &Review, aliases: &impl AliasStore) -> Value {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns JSON for a `Comment`.
|
/// Returns JSON for a Issue `Comment`.
|
||||||
fn comment(id: &CommentId, comment: &Comment, aliases: &impl AliasStore) -> Value {
|
fn issue_comment(id: &CommentId, comment: &Comment, aliases: &impl AliasStore) -> Value {
|
||||||
json!({
|
json!({
|
||||||
"id": *id,
|
"id": *id,
|
||||||
"author": author(&Author::from(comment.author()), aliases.alias(&comment.author())),
|
"author": author(&Author::from(comment.author()), aliases.alias(&comment.author())),
|
||||||
|
|
@ -194,6 +194,33 @@ fn comment(id: &CommentId, comment: &Comment, aliases: &impl AliasStore) -> Valu
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns JSON for a Patch `Comment`.
|
||||||
|
fn patch_comment(
|
||||||
|
id: &CommentId,
|
||||||
|
comment: &Comment<CodeLocation>,
|
||||||
|
aliases: &impl AliasStore,
|
||||||
|
) -> Value {
|
||||||
|
json!({
|
||||||
|
"id": *id,
|
||||||
|
"author": author(&Author::from(comment.author()), aliases.alias(&comment.author())),
|
||||||
|
"body": comment.body(),
|
||||||
|
"edits": comment.edits().map(|edit| {
|
||||||
|
json!({
|
||||||
|
"author": author(&Author::from(edit.author), aliases.alias(&edit.author)),
|
||||||
|
"body": edit.body,
|
||||||
|
"timestamp": edit.timestamp.as_secs(),
|
||||||
|
"embeds": edit.embeds,
|
||||||
|
})
|
||||||
|
}).collect::<Vec<_>>(),
|
||||||
|
"embeds": comment.embeds().to_vec(),
|
||||||
|
"reactions": comment.reactions().collect::<Vec<_>>(),
|
||||||
|
"timestamp": comment.timestamp().as_secs(),
|
||||||
|
"replyTo": comment.reply_to(),
|
||||||
|
"location": comment.location(),
|
||||||
|
"resolved": comment.resolved(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns JSON for a `Review`.
|
/// Returns JSON for a `Review`.
|
||||||
fn review_comment(
|
fn review_comment(
|
||||||
id: &CommentId,
|
id: &CommentId,
|
||||||
|
|
|
||||||
|
|
@ -3041,6 +3041,7 @@ mod routes {
|
||||||
"reactions": [["z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8","🚀"]],
|
"reactions": [["z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8","🚀"]],
|
||||||
"timestamp": TIMESTAMP,
|
"timestamp": TIMESTAMP,
|
||||||
"replyTo": null,
|
"replyTo": null,
|
||||||
|
"location": null,
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -3063,6 +3064,7 @@ mod routes {
|
||||||
"reactions": [],
|
"reactions": [],
|
||||||
"timestamp": TIMESTAMP,
|
"timestamp": TIMESTAMP,
|
||||||
"replyTo": comment_id,
|
"replyTo": comment_id,
|
||||||
|
"location": null,
|
||||||
"resolved": false,
|
"resolved": false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1012,7 +1012,7 @@ impl Patch {
|
||||||
body,
|
body,
|
||||||
reply_to,
|
reply_to,
|
||||||
embeds,
|
embeds,
|
||||||
..
|
location,
|
||||||
} => {
|
} => {
|
||||||
if let Some(revision) = lookup::revision_mut(self, &revision)? {
|
if let Some(revision) = lookup::revision_mut(self, &revision)? {
|
||||||
thread::comment(
|
thread::comment(
|
||||||
|
|
@ -1022,7 +1022,7 @@ impl Patch {
|
||||||
timestamp,
|
timestamp,
|
||||||
body,
|
body,
|
||||||
reply_to,
|
reply_to,
|
||||||
None,
|
location,
|
||||||
embeds,
|
embeds,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
@ -1255,7 +1255,7 @@ pub struct Revision {
|
||||||
/// Reference to the Git object containing the code (revision head).
|
/// Reference to the Git object containing the code (revision head).
|
||||||
pub(super) oid: git::Oid,
|
pub(super) oid: git::Oid,
|
||||||
/// Discussion around this revision.
|
/// Discussion around this revision.
|
||||||
pub(super) discussion: Thread<Comment>,
|
pub(super) discussion: Thread<Comment<CodeLocation>>,
|
||||||
/// Reviews of this revision's changes (one per actor).
|
/// Reviews of this revision's changes (one per actor).
|
||||||
pub(super) reviews: BTreeMap<ActorId, Option<Review>>,
|
pub(super) reviews: BTreeMap<ActorId, Option<Review>>,
|
||||||
/// When this revision was created.
|
/// When this revision was created.
|
||||||
|
|
@ -1313,7 +1313,7 @@ impl Revision {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Discussion around this revision.
|
/// Discussion around this revision.
|
||||||
pub fn discussion(&self) -> &Thread<Comment> {
|
pub fn discussion(&self) -> &Thread<Comment<CodeLocation>> {
|
||||||
&self.discussion
|
&self.discussion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
use std::convert::Infallible;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
@ -67,7 +68,7 @@ pub struct Edit {
|
||||||
|
|
||||||
/// A comment on a discussion thread.
|
/// A comment on a discussion thread.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Comment<T = ()> {
|
pub struct Comment<T = Infallible> {
|
||||||
/// Comment author.
|
/// Comment author.
|
||||||
author: ActorId,
|
author: ActorId,
|
||||||
/// The comment body.
|
/// The comment body.
|
||||||
|
|
@ -265,7 +266,7 @@ impl From<Action> for nonempty::NonEmpty<Action> {
|
||||||
|
|
||||||
/// A discussion thread.
|
/// A discussion thread.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Thread<T = Comment<()>> {
|
pub struct Thread<T = Comment> {
|
||||||
/// The comments under the thread.
|
/// The comments under the thread.
|
||||||
pub(crate) comments: BTreeMap<CommentId, Option<T>>,
|
pub(crate) comments: BTreeMap<CommentId, Option<T>>,
|
||||||
/// Comment timeline.
|
/// Comment timeline.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue