Skip to content

Commit

Permalink
partial hover event
Browse files Browse the repository at this point in the history
Co-authored-by: Yjn024 <[email protected]>
  • Loading branch information
0123456789-jpg and JieningYu committed Nov 8, 2023
1 parent ae1837c commit ed18f66
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 89 deletions.
1 change: 1 addition & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ bimap = "0.6"
thiserror = "1.0"
rsa = "0.9"
enumn = "0.1"
erased-serde = "0.3"
158 changes: 85 additions & 73 deletions core/src/text/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use parking_lot::RwLock;
use serde::{Deserialize, Serialize};

use rimecraft_event::Event;
use rimecraft_primitives::{id, ErasedSerDeUpdate, Id};
use rimecraft_primitives::{id, ErasedSerDeUpdate, Id, SerDeUpdate};

use crate::Rgb;

use super::formatting::Formatting;

Expand All @@ -27,6 +29,8 @@ pub enum Error {
ParseInt(std::num::ParseIntError),
#[error("formatting error: {0}")]
Formatting(super::formatting::Error),
#[error("invalid name: {0}")]
InvalidName(String),
}

/// TODO: Implement net.minecraft.text.Text
Expand All @@ -39,7 +43,7 @@ pub trait Text {

/// The style of a [`Text`].\
/// A style is immutable.
#[derive(PartialEq, Eq)]
#[derive(PartialEq)]
pub struct Style {
color: Option<Color>,
bold: Option<bool>,
Expand Down Expand Up @@ -130,39 +134,40 @@ impl Style {
/// # MCJE Reference
///
/// This type represents `net.minecraft.text.TextColor` (yarn).
#[derive(Debug, Hash)]
#[derive(Debug, Hash, Eq)]
pub struct Color {
/// A 24-bit color.
rgb: u32,
name: Option<Cow<'static, str>>,
rgb: Rgb,
name: Option<&'static str>,
}

impl Color {
const RGB_PREFIX: &str = "#";

#[inline]
pub fn from_rgb(rgb: u32) -> Self {
Self { rgb, name: None }
pub fn rgb(&self) -> Rgb {
self.rgb
}

#[inline]
pub fn new(rgb: u32, name: Cow<'static, str>) -> Self {
Self {
rgb,
name: Some(name),
}
}

#[inline]
fn as_hex_str(&self) -> String {
fn to_hex_code(&self) -> String {
format!("{}{:06X}", Self::RGB_PREFIX, self.rgb)
}

#[inline]
pub fn name(&self) -> Cow<'_, str> {
pub fn name(&self) -> Cow<'static, str> {
self.name
.clone()
.unwrap_or_else(|| Cow::Owned(self.as_hex_str()))
.map(|e| Cow::Borrowed(e))
.unwrap_or_else(|| Cow::Owned(self.to_hex_code()))
}
}

impl Display for Color {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(name) = self.name {
f.write_str(name)
} else {
f.write_str(&self.to_hex_code())
}
}
}

Expand All @@ -171,54 +176,48 @@ impl FromStr for Color {

fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Some(value) = s.strip_prefix(Self::RGB_PREFIX) {
Ok(Self::from_rgb(value.parse().map_err(Error::ParseInt)?))
} else {
let f: Formatting = s.parse().map_err(Error::Formatting)?;
Ok(Self {
rgb: f.color_value().ok_or(Error::ColorValueNotFound)?,
name: Some(Cow::Borrowed(f.name())),
rgb: value.parse().map_err(Error::ParseInt)?,
name: None,
})
} else {
s.parse::<Formatting>()
.map_err(Error::Formatting)?
.try_into()
}
}
}

impl TryFrom<&'static Formatting> for Color {
impl TryFrom<Formatting> for Color {
type Error = Error;

fn try_from(value: &'static Formatting) -> Result<Self, Self::Error> {
if value.is_color() {
Ok(Self {
rgb: value.color_value().unwrap(),
name: Some(Cow::Borrowed(value.name())),
})
} else {
Err(Error::InvalidColor)
}
fn try_from(value: Formatting) -> Result<Self, Self::Error> {
Ok(Self {
rgb: value.color_value().ok_or(Error::ColorValueNotFound)?,
name: Some(value.name()),
})
}
}

impl PartialEq for Color {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.rgb == other.rgb
}
}

impl Eq for Color {}

impl Display for Color {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = self.name();
write!(f, "{name}")
}
}

#[derive(Hash, PartialEq, Eq)]
#[derive(Hash, PartialEq, Eq, Debug)]
pub struct ClickEvent {
action: ClickEventAction,
value: String,
}

impl ClickEvent {
#[inline]
pub fn new(action: ClickEventAction, value: String) -> Self {
Self { action, value }
}

#[inline]
pub fn action(&self) -> ClickEventAction {
self.action
Expand All @@ -228,20 +227,6 @@ impl ClickEvent {
pub fn value(&self) -> &str {
&self.value
}

#[inline]
pub fn new(action: ClickEventAction, value: String) -> Self {
Self { action, value }
}
}

impl Debug for ClickEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let action = self.action().name();
let value = self.value();

write!(f, "ClickEvent{{action={action}, value='{value}'}}")
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -280,23 +265,31 @@ impl ClickEventAction {
pub fn is_user_definable(self) -> bool {
!matches!(self, Self::OpenFile)
}
}

#[inline]
pub fn from_name(name: &str) -> Option<Self> {
impl FromStr for ClickEventAction {
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
static MAP: Lazy<HashMap<String, ClickEventAction>> = Lazy::new(|| {
ClickEventAction::VALUES
.into_iter()
.map(|value| (value.name().to_owned(), value))
.collect()
});

MAP.get(name).copied()
MAP.get(s)
.copied()
.ok_or_else(|| Error::InvalidName(s.to_owned()))
}
}

trait UpdDebug: ErasedSerDeUpdate + Debug {}
impl<T> UpdDebug for T where T: ?Sized + ErasedSerDeUpdate + Debug {}

erased_serde::serialize_trait_object!(UpdDebug);
rimecraft_primitives::update_trait_object!(UpdDebug);

pub struct HoverEvent {
contents: (Arc<dyn UpdDebug + Send + Sync>, TypeId),
action: &'static HoverEventAction,
Expand Down Expand Up @@ -334,15 +327,6 @@ impl HoverEvent {
}
}

impl Serialize for HoverEvent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
todo!()
}
}

impl Hash for HoverEvent {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
Expand All @@ -368,7 +352,33 @@ impl PartialEq for HoverEvent {
}
}

impl Eq for HoverEvent {}
impl Serialize for HoverEvent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer {
#[derive(Serialize)]
struct Struct<'a> {
action: &'static HoverEventAction,
contents: &'a (dyn UpdDebug + Send + Sync),
}

Struct {
action: self.action,
contents: &*self.contents.0,
}.serialize(serializer)
}
}

impl SerDeUpdate for HoverEvent {
fn update<'de, D>(
&'de mut self,
deserializer: D,
) -> Result<(), <D as serde::Deserializer<'_>>::Error>
where
D: serde::Deserializer<'de> {
todo!()
}
}

#[derive(PartialEq, Eq, Clone, Hash)]
pub struct HoverEventAction {
Expand Down Expand Up @@ -436,11 +446,12 @@ impl HoverEventAction {
impl Debug for HoverEventAction {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<action {}>", self.name)
f.debug_struct("HoverEventAction").field("name", &self.name).finish()
}
}

impl Serialize for HoverEventAction {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
Expand All @@ -456,6 +467,7 @@ impl<'de> Deserialize<'de> for &'static HoverEventAction {
{
static VARIANTS: Lazy<Vec<&'static str>> =
Lazy::new(|| HE_MAPPING.iter().map(|v| v.0.as_str()).collect());

let value = String::deserialize(deserializer)?;

use serde::de::Error;
Expand Down
54 changes: 47 additions & 7 deletions core/src/util/formatting.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,41 @@
use std::{borrow::Cow, collections::HashMap, ops::Deref, str::FromStr};
use std::{collections::HashMap, fmt::Display, ops::Deref, str::FromStr};

use once_cell::sync::Lazy;

use super::ColorIndex;
use super::Rgb;

#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct ColorIndex {
value: i8,
}

impl ColorIndex {
#[inline]
pub fn new(value: Option<u8>) -> Self {
Self {
value: value.map(|e| e as i8).unwrap_or(-1),
}
}

#[inline]
pub fn value(self) -> Option<u8> {
if self.value == -1 {
None
} else {
Some(self.value as u8)
}
}
}

impl Default for ColorIndex {
#[inline]
fn default() -> Self {
Self { value: -1 }
}
}

macro_rules! formattings {
($( $i:ident => $n:expr, $c:expr, $m:expr, $ci:expr, $cv:expr ),+,) => {
($( $i:ident => $n:literal, $c:literal, $m:expr, $ci:literal, $cv:expr ),+,) => {
/// An enum holding formattings.
///
/// There are two types of formattings, color and modifier. Color formattings
Expand All @@ -22,8 +52,6 @@ macro_rules! formattings {
}

impl Formatting {
const CODE_PREFIX: char = '§';

#[inline]
fn name_raw(self) -> &'static str {
match self {
Expand Down Expand Up @@ -67,10 +95,10 @@ macro_rules! formattings {
/// Returns the color of the formatted text, or
/// `None` if the formatting has no associated color.
#[inline]
pub fn color_value(self) -> Option<u32> {
pub fn color_value(self) -> Option<Rgb> {
match self {
$(
Formatting::$i => $cv,
Formatting::$i => $cv.map(Rgb::new),
)*
}
}
Expand Down Expand Up @@ -131,6 +159,8 @@ pub enum Error {
}

impl Formatting {
const CODE_PREFIX: char = '§';

/// Returns `true` if the formatting is associated with
/// a color, `false` otherwise.
#[inline]
Expand Down Expand Up @@ -188,6 +218,16 @@ impl FromStr for Formatting {
}
}

impl Display for Formatting {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use std::fmt::Write;

f.write_char(Self::CODE_PREFIX)?;
f.write_char(self.code())
}
}

impl TryFrom<ColorIndex> for Formatting {
type Error = Error;

Expand Down
Loading

0 comments on commit ed18f66

Please sign in to comment.