Skip to content

Commit

Permalink
docs
Browse files Browse the repository at this point in the history
  • Loading branch information
JieningYu committed Nov 11, 2023
1 parent 5f8420c commit aa68a28
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 42 deletions.
7 changes: 6 additions & 1 deletion core/src/text/hover_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ erased_serde::serialize_trait_object!(UpdDebug);
rimecraft_primitives::update_trait_object!(UpdDebug);

/// Event performed when cursor is hovering on a `Text`.
///
/// # MCJE Reference
///
/// This type represents `net.minecraft.text.HoverEvent` (yarn).
pub struct HoverEvent {
contents: Box<dyn UpdDebug + Send + Sync>,
action: &'static ErasedAction,
Expand Down Expand Up @@ -114,7 +118,7 @@ impl<'de> Deserialize<'de> for HoverEvent {
contents: serde_json::Value,
}

//TODO: if `contents` is invalid, deserialize text from field `value`.
//TODO: if `contents` not found, deserialize text from field `value`.
let Struct { action, contents } = Struct::deserialize(deserializer)?;

// Deserializing contents.
Expand All @@ -139,6 +143,7 @@ pub struct Action<T> {
factory: fn() -> T,
}

/// Registers an action.
pub fn register_action<T: 'static>(action: Action<T>)
where
T: ErasedSerDeUpdate + Debug + Send + Sync,
Expand Down
105 changes: 83 additions & 22 deletions core/src/text/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@ use std::{

use rimecraft_primitives::{id, Id};

use crate::Rgb;
use crate::RGB;

use self::{click_event::ClickEvent, hover_event::HoverEvent};

use super::formatting::Formatting;
use super::fmt::Formatting;

pub mod click_event;
pub mod hover_event;

pub mod visit;

pub use click_event::ClickEvent;
pub use hover_event::HoverEvent;

/// An error that can occur when processing a [`Text`].
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("not a valid color")]
Expand All @@ -27,37 +29,63 @@ pub enum Error {
#[error("unable to parse integer: {0}")]
ParseInt(std::num::ParseIntError),
#[error("formatting error: {0}")]
Formatting(super::formatting::Error),
Formatting(super::fmt::Error),
#[error("invalid name: {0}")]
InvalidName(String),
}

/// TODO: Implement net.minecraft.text.Text
//TODO: Implement net.minecraft.text.Text
pub trait Text {
fn style(&self) -> &Style;
fn siblings(&self) -> Vec<Box<dyn Text>>;
/// TODO: Implement net.minecraft.text.OrderedText
fn as_ordered_text(&self) -> ();
//TODO: Implement net.minecraft.text.OrderedText
fn as_ordered_text(&self);
}

/// The style of a [`Text`].\
/// A style is immutable.
#[derive(PartialEq)]
/// The style of a [`Text`], representing cosmetic attributes.
/// It includes font, color, click event, hover event, etc.
///
/// A style should be immutable.
///
/// # MCJE Reference
///
/// This type represents `net.minecraft.text.Style` (yarn).
#[derive(PartialEq, Debug, Default)]
pub struct Style {
/// The color of this style.
pub color: Option<Color>,

/// Whether this style has bold formatting.
pub bold: Option<bool>,

/// Whether this style has italic formatting.
pub italic: Option<bool>,

/// Whether this style has underlined formatting.
pub underlined: Option<bool>,

/// Whether this style has strikethrough formatting.
pub strikethrough: Option<bool>,

/// Whether this style has obfuscated formatting.
pub obfuscated: Option<bool>,

/// The click event of this style.
pub click: Option<ClickEvent>,

/// The hover event of this style.
pub hover: Option<HoverEvent>,

/// The insertion text of this style.
pub insertion: Option<String>,

/// The font ID of this style.
pub font: Option<Id>,
}

impl Style {
const EMPTY: Self = Self {
/// An empty style.
pub const EMPTY: Self = Self {
color: None,
bold: None,
italic: None,
Expand All @@ -72,52 +100,82 @@ impl Style {

const DEFAULT_FONT_ID: &str = "default";

/// Returns the color of this style.
#[inline]
pub fn color(&self) -> Option<&Color> {
self.color.as_ref()
}

/// Returns whether this style has bold formatting.
///
/// See [`Formatting::Bold`].
#[inline]
pub fn bold(&self) -> bool {
pub fn is_bold(&self) -> bool {
self.bold.unwrap_or(false)
}

/// Returns whether this style has italic formatting.
///
/// See [`Formatting::Italic`].
#[inline]
pub fn italic(&self) -> bool {
pub fn is_italic(&self) -> bool {
self.italic.unwrap_or(false)
}

/// Returns whether this style has strikethrough formatting.
///
/// See [`Formatting::Strikethrough`].
#[inline]
pub fn strikethrough(&self) -> bool {
pub fn is_strikethrough(&self) -> bool {
self.strikethrough.unwrap_or(false)
}

/// Returns whether this style has underlined formatting.
///
/// See [`Formatting::Underline`].
#[inline]
pub fn underlined(&self) -> bool {
pub fn is_underlined(&self) -> bool {
self.underlined.unwrap_or(false)
}

/// Returns whether this style has obfuscated formatting.
///
/// See [`Formatting::Obfuscated`].
#[inline]
pub fn obfuscated(&self) -> bool {
pub fn is_obfuscated(&self) -> bool {
self.obfuscated.unwrap_or(false)
}

pub fn empty(&self) -> bool {
/// Returns whether this style is empty.
///
/// See [`Self::EMPTY`].
#[inline]
pub fn is_empty(&self) -> bool {
self == &Self::EMPTY
}

pub fn click(&self) -> Option<&ClickEvent> {
/// Returns the click event of this style.
#[inline]
pub fn click_event(&self) -> Option<&ClickEvent> {
self.click.as_ref()
}

pub fn hover(&self) -> Option<&HoverEvent> {
/// Returns the hover event of this style.
#[inline]
pub fn hover_event(&self) -> Option<&HoverEvent> {
self.hover.as_ref()
}

/// Returns the insertion text of this style.
///
/// An insertion text is a text that is inserted into the chat
/// when the player shift-clicks on the text.
#[inline]
pub fn insertion(&self) -> Option<&String> {
self.insertion.as_ref()
}

/// Returns the font ID of this style.
pub fn font(&self) -> Cow<'_, Id> {
self.font
.as_ref()
Expand All @@ -135,23 +193,26 @@ impl Style {
#[derive(Debug, Eq)]
pub struct Color {
/// A 24-bit color.
rgb: Rgb,
rgb: RGB,
name: Option<&'static str>,
}

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

/// Returns the inner RGB value of this color.
#[inline]
pub fn rgb(&self) -> Rgb {
pub fn rgb(&self) -> RGB {
self.rgb
}

/// Returns the hex code of this color.
#[inline]
fn to_hex_code(&self) -> String {
format!("{}{:06X}", Self::RGB_PREFIX, self.rgb)
}

/// Returns the name of this color.
pub fn name(&self) -> Cow<'static, str> {
self.name
.map(Cow::Borrowed)
Expand Down
32 changes: 23 additions & 9 deletions core/src/util/formatting.rs → core/src/util/fmt.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
use std::{collections::HashMap, fmt::Display, ops::Deref, str::FromStr};

use fastnbt::de;
use once_cell::sync::Lazy;

use super::Rgb;
use super::RGB;

/// An index of a color in [`Formatting`].
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct ColorIndex {
value: i8,
}

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

/// Returns the value of the color index if valid.
#[inline]
pub fn value(self) -> Option<u8> {
if self.value == -1 {
Expand All @@ -40,7 +44,7 @@ macro_rules! formattings {
///
/// There are two types of formattings, color and modifier. Color formattings
/// are associated with a specific color, while modifier formattings modify the
/// style, such as by bolding the text. [`Self::RESET`] is a special formatting
/// style, such as by bolding the text. [`Self::Reset`] is a special formatting
/// and is not classified as either of these two.
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
Expand Down Expand Up @@ -95,10 +99,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<Rgb> {
pub fn color_value(self) -> Option<RGB> {
match self {
$(
Formatting::$i => $cv.map(Rgb::new),
Formatting::$i => $cv.map(RGB::new),
)*
}
}
Expand Down Expand Up @@ -148,18 +152,23 @@ formattings! {
Reset => "RESET", 'r', false, -1, None,
}

/// An error returned when parsing a formatting.
#[derive(thiserror::Error, Debug)]
pub enum Error {
/// No matching color index found.
#[error("no matching color index {0:?} found")]
NoMatchingColorIndex(ColorIndex),
/// Invalid code.
#[error("invalid code: {0}")]
InvalidCode(char),
/// Invalid name.
#[error("invalid name: {0}")]
InvalidName(String),
}

impl Formatting {
const CODE_PREFIX: char = '§';
/// The prefix of formatting codes.
pub const CODE_PREFIX: char = '§';

/// Returns `true` if the formatting is associated with
/// a color, `false` otherwise.
Expand All @@ -173,7 +182,7 @@ impl Formatting {
pub fn name(self) -> &'static str {
static NAMING_MAP: Lazy<Vec<String>> = Lazy::new(|| {
Formatting::values()
.into_iter()
.iter()
.map(|e| e.name_raw().to_ascii_lowercase())
.collect()
});
Expand All @@ -189,6 +198,7 @@ impl Formatting {
}
}

/// Sanitize a formatting name.
#[inline]
fn name_sanitize(name: &str) -> String {
lazy_regex::regex_replace_all!("[^a-z]", &name.to_lowercase(), "").into_owned()
Expand All @@ -207,7 +217,7 @@ impl FromStr for Formatting {
fn from_str(s: &str) -> Result<Self, Self::Err> {
static NAME_MAP: Lazy<HashMap<String, Formatting>> = Lazy::new(|| {
Formatting::values()
.into_iter()
.iter()
.map(|e| (name_sanitize(e.name_raw()), *e))
.collect()
});
Expand Down Expand Up @@ -238,7 +248,7 @@ impl TryFrom<ColorIndex> for Formatting {
} else {
static CI_MAP: Lazy<HashMap<ColorIndex, Formatting>> = Lazy::new(|| {
Formatting::values()
.into_iter()
.iter()
.map(|e| (e.color_index(), *e))
.collect()
});
Expand All @@ -257,7 +267,7 @@ impl TryFrom<char> for Formatting {
fn try_from(value: char) -> Result<Self, Self::Error> {
static CHAR_MAP: Lazy<HashMap<char, Formatting>> = Lazy::new(|| {
Formatting::values()
.into_iter()
.iter()
.map(|e| (e.code(), *e))
.collect()
});
Expand All @@ -269,6 +279,7 @@ impl TryFrom<char> for Formatting {
}

/// The iterator returned by [`Formatting::names`].
#[derive(Debug)]
pub struct Names {
iter: std::slice::Iter<'static, Formatting>,
}
Expand All @@ -283,16 +294,19 @@ impl Iterator for Names {
}

/// Item of [`Names`].
#[derive(Debug)]
pub struct Name {
value: Formatting,
}

impl Name {
/// Returns whether the targeting formatting is a color.
#[inline]
pub fn is_color(&self) -> bool {
self.value.is_color()
}

/// Returns whether the targeting formatting is a modifier.
#[inline]
pub fn is_modifier(&self) -> bool {
self.value.is_modifier()
Expand Down
Loading

0 comments on commit aa68a28

Please sign in to comment.