// ----- alice: claim alices' hand -----
let [hand] = a_pieces.iter_enumerated()
- .filter(|(_i,p)| p.info["desc"] == otter::hand::UNCLAIMED_DESC)
+ .filter(|(_i,p)| {
+ p.info["desc"] == otter::hand::UNCLAIMED_DESC.as_html_str()
+ })
.map(|(i,_)| i)
.collect::<ArrayVec<[_;1]>>()
.into_inner().unwrap();
let pri = piece_pri(ioccults, &gs.occults, player, gpl, piece, gpc, ipc)
.ok_or(POE::PieceGone)?;
- let pcs = pri.describe(ioccults,&gs.occults, gpc, ipc).0;
+ let pcs = pri.describe(ioccults,&gs.occults, gpc, ipc);
gpc.held = Some(player);
let pls = &htmlescape::encode_minimal(&gpl.nick);
- let logent = LogEntry { html: Html(match was {
- Some(was) => format!("{} wrested {} from {}", pls, pcs, was),
- None => format!("{} wrested {}", pls, pcs),
- })};
+ let logent = LogEntry { html: match was {
+ Some(was) => hformat!("{} wrested {} from {}", pls, pcs, was),
+ None => hformat!("{} wrested {}", pls, pcs),
+ }};
(WhatResponseToClientOp::Predictable,
update, vec![logent]).into()
let auth = authorise_by_account(cs, &ag, &game)?;
let gs = otter::gamestate::GameState {
- table_colour: Html::lit("green"),
+ table_colour: Html::lit("green").into(),
table_size: DEFAULT_TABLE_SIZE,
pieces: default(),
players: default(),
ig.gs.table_size = size;
(U{ pcs: vec![],
log: vec![ LogEntry {
- html: Html(format!("{} resized the table to {}x{}",
- &who.0, size.x(), size.y())),
+ html: hformat!("{} resized the table to {}x{}",
+ who, size.x(), size.y()),
}],
raw: Some(vec![ PreparedUpdateEntry::SetTableSize(size) ]) },
Fine, None, ig)
ig.gs.table_colour = colour.clone();
(U{ pcs: vec![],
log: vec![ LogEntry {
- html: Html(format!("{} recoloured the tabletop to {}",
- &who.0, &colour.0)),
+ html: hformat!("{} recoloured the tabletop to {}",
+ &who, &colour),
}],
raw: Some(vec![ PreparedUpdateEntry::SetTableColour(colour) ]) },
Fine, None, ig)
let (ig, auth) = cs.check_acl(ag, ig, PCH::Instance, &[TP::Play])?;
let nick = nick.ok_or(ME::MustSpecifyNick)?;
let logentry = LogEntry {
- html: Html(format!("{} [{}] joined the game", &nick, &account)),
+ html: hformat!("{} [{}] joined the game", nick, account),
};
let timezone = &arecord.timezone;
let tz = tz_from_str(&timezone);
ig.check_new_nick(&new_nick)?;
let gpl = ig.gs.players.byid_mut(player)?;
log.push(LogEntry {
- html: Html(format!("{} changed {}'s nick to {}",
- &who.0,
- htmlescape::encode_minimal(&gpl.nick),
- htmlescape::encode_minimal(&new_nick))),
+ html: hformat!("{} changed {}'s nick to {}",
+ &who, gpl.nick, new_nick),
});
gpl.nick = new_nick;
}
}
let new_links = Arc::new(new_links);
*ig_links = new_links.clone();
- Ok(Html(
- format!("{} set the links to off-server game resources",
- &who.0)
- ))
+ Ok(
+ hformat!("{} set the links to off-server game resources",
+ who)
+ )
})?
}
new_links[kind] = Some(url.into_string());
let new_links = Arc::new(new_links);
*ig_links = new_links.clone();
- Ok(Html(
- format!("{} set the link {}",
- &who.0, &show.0)
- ))
+ Ok(
+ hformat!("{} set the link {}",
+ who, show)
+ )
})?
}
new_links[kind] = None;
let new_links = Arc::new(new_links);
*ig_links = new_links.clone();
- Ok(Html(
- format!("{} removed the link {}",
- &who.0, &kind)
- ))
+ Ok(
+ hformat!("{} removed the link {}",
+ who, &kind)
+ )
})?
}
let (gpl, ipl, update) = got.into_iter().next()
.ok_or(PlayerNotFound)?;
- let html = Html(
- format!("{} [{}] left the game [{}]"
+ let html =
+ hformat!("{} [{}] left the game [{}]"
,
(|| Some(gpl?.nick))()
.unwrap_or("<partial data!>".into())
,
&account
)
- );
+ ;
(U{ pcs: vec![],
log: vec![ LogEntry { html }],
let pri = PieceRenderInstructions::new_visible(default());
pri.describe(ioccults,&gs.occults, gpc, &ipc)
} else {
- Html::lit("<piece partially missing from game state!>")
+ "<piece partially missing from game state>".to_html()
};
if let Some(gpc) = gpc {
ipc.p.into_inner().delete_hook(&gpc, gs);
if let Some(occilk) = ipc.occilk { ig.ioccults.ilks.dispose(occilk); }
(U{ pcs: vec![(piece, PieceUpdateOp::Delete())],
log: vec![ LogEntry {
- html: Html(format!("A piece {} was removed from the game",
- desc_html.0)),
+ html: hformat!("A piece {} was removed from the game",
+ desc_html),
}],
raw: None },
Fine,
(U{ pcs: updates,
log: vec![ LogEntry {
- html: Html(format!("{} added {} pieces", &who.0, count_len)),
+ html: hformat!("{} added {} pieces", who, count_len),
}],
raw: None },
Fine, None, ig_g)
}
(U{ pcs: vec![ ],
log: vec![ LogEntry {
- html: Html(format!("{} cleared the log", &who.0)),
+ html: hformat!("{} cleared the log", who),
} ],
raw: None },
Fine, None, ig)
let (ig, _) = cs.check_acl(&ag, ig, PCH::Instance, &[TP::Super])?;
ig.acl = acl.into();
let mut log = vec![ LogEntry {
- html: Html(format!("{} set the table access control list",
- &who.0)),
+ html: hformat!("{} set the table access control list",
+ who),
} ];
#[throws(InternalError)]
"<i>partial data?!</i>".to_string()
};
log.push(LogEntry {
- html: Html(format!("{} removed a player {}", &who.0, &show)),
+ html: hformat!("{} removed a player {}", who, show),
});
updates.push(update);
}
.filter(|(_,ipr)| ipr.ipl.acctid == acctid)
.next();
if let Some(gpl) = ig.gs.players.get(player);
- then { Html(format!("{} [{}]",
- &htmlescape::encode_minimal(&gpl.nick),
- &account)) }
- else { Html(format!("[{}]",
- &account)) }
+ then { hformat!("{} [{}]",
+ gpl.nick,
+ account) }
+ else { hformat!("[{}]",
+ account) }
};
let res = (||{
for insn in insns.drain(0..) {
if bulk.logs {
buf.log_updates(vec![LogEntry {
- html: Html(format!("{} (re)configured the game", &who.0)),
+ html: hformat!("{} (re)configured the game", who),
}]);
}
l.into_iter()
.map(|(trk,trv)|{
let when = trv.latest;
- let html = Html(format!(
+ let html = hformat!(
"player state accessed via {} [{}]",
- &trk.desc.0, &trk.account
- ));
+ trk.desc, trk.account
+ );
Arc::new(CommittedLogEntry { when, logent: LogEntry { html } })
})
},
], |s| f.write_str(s))?
}
}
+hformat_as_display!{ AccountName }
impl FromStr for AccountName {
type Err = InvalidScopedName;
println!(r#"<table rules="all">"#);
for s in &pieces {
let Prep { spec, p, uos, bbox, size } = s;
+
+ macro_rules! println {
+ ($($x:tt)*) => ({
+ let mut s = Html::new();
+ hwrite!(&mut s, $($x)*).unwrap();
+ std::println!("{}", &s.as_html_str());
+ })
+ }
+
println!(r#"<tr>"#);
println!(r#"<th align="left"><kbd>{}</kbd></th>"#,
- Html::from_txt(&spec.lib).0);
+ Html::from_txt(&spec.lib));
println!(r#"<th align="left"><kbd>{}</kbd></th>"#,
- Html::from_txt(&spec.item).0);
+ Html::from_txt(&spec.item));
println!(r#"<th align="left">{}</th>"#,
- p.describe_html(&GPiece::dummy(), &default())?.0);
+ p.describe_html(&GPiece::dummy(), &default())?);
let only1 = s.face_cols() == 1;
for facecol in 0..(if only1 { 1 } else { max_facecols }) {
&viewport, wh[0], wh[1]);
if inseveral == 1 {
let dasharray = player_num_dasharray(1.try_into().unwrap());
- print!(r#"<path d="{}" stroke-dasharray="{}"
+ println!(r#"<path d="{}" stroke-dasharray="{}"
fill="none" stroke="{}" />"#,
- &surround.0, &dasharray.0, HELD_SURROUND_COLOUR);
+ &surround, &dasharray, HELD_SURROUND_COLOUR);
}
- let mut html = Html("".into());
+ let mut html = Html::lit("").into();
let gpc = GPiece { face: face.into(), ..GPiece::dummy() };
p.svg_piece(&mut html, &gpc, &GameState::dummy(), default())?;
- println!("{}</svg>", html.0);
+ println!("{}</svg>", html);
}
println!("</td>");
if max_uos > 0 {
println!(r#"<td>{}</td>"#,
uos.iter()
- .map(|uo| Html::from_txt(uo).0)
- .join(" "));
+ .map(|uo| Html::from_txt(uo))
+ .collect::<Vec<Html>>()
+ .iter()
+ .hjoin(&Html::lit(" ")));
}
};
println!("</tr>");
write!(f, "User({})", self)
}
}
+hformat_as_display!{User}
#[derive(Debug,Clone,Copy,Error,Serialize,Deserialize)]
struct BadClockUserError;
#[throws(IE)]
fn svg_piece(&self, f: &mut Html, gpc: &GPiece, gs: &GameState,
vpid: VisiblePieceId) {
- let f = &mut f.0;
let state = gpc.xdata()?
.ok_or_else(|| internal_logic_error("missing/wrong xdata"))?;
let urenders = self.urender(&state, gpc.held, &gs.players);
}
}
- write!(f, r##"
+ hwrite!(f, r##"
<g transform="translate(-20,-7)">"##,
)?;
for (y, u) in izip!(Y.iter(), urenders.iter()) {
- write!(f, r##"
+ hwrite!(f, r##"
<rect y="{}" fill="{}" width="40" height="7"/>"##,
- y,
- u.st.show().background,
+ y,
+ Html::lit(u.st.show().background),
)?;
}
- write!(f, r##"
+ hwrite!(f, r##"
<rect fill="none" stroke="black" width="40" height="14"></rect>
<clipPath id="def.{}.cl"><rect width="40" height="14"></rect></clipPath>"##,
- vpid
+ &vpid
)?;
for (user, y, u) in izip!(USERS.iter(), Y.iter(), urenders.iter()) {
let y = y + 6.;
let mins = u.remaining.tv_sec() / 60;
let secs = u.remaining.tv_sec() % 60;
let mins = mins.to_string();
- let mins_pad = iter::repeat(" ").take(3 - mins.len())
- .collect::<String>();
+ let mins_pad = Html::from_html_string(
+ iter::repeat(" ").take(3 - mins.len())
+ .collect()
+ );
- let pointer = r##"
+ let pointer = Html::lit(r##"
pointer-events="none"
- "##;
- let font = r##"
+ "##);
+ let font = Html::lit(r##"
font-family="Latin Modern Mono, monospace" font-size="6" font-weight="700"
- "##;
- write!(f, r##"
+ "##);
+ hwrite!(f, r##"
<text x="1" y="{}" {} {} fill="{}" >{}{}{}</text>"##,
- y, font, pointer, show.text,
- mins_pad, mins, show.sigil
+ y, font, pointer, Html::lit(show.text),
+ mins_pad, HtmlStr::from_html_str(&mins), Html::lit(show.sigil)
)?;
- write!(f, r##"
+ hwrite!(f, r##"
<text x="14" y="{}" {} {} fill="{}" >{:02}</text>"##,
- y, font, pointer, show.text,
+ y, font, pointer, Html::lit(show.text),
secs
)?;
let nick_y = y - 0.5;
if let Some(nick) = u.nick {
- write!(f, r##"
+ hwrite!(f, r##"
<text x="21" y="{}" {} clip-path="url(#def.{}.cl)" font-size="4">{}</text>
"##,
nick_y, pointer,
vpid,
- htmlescape::encode_minimal(nick),
+ nick,
)?;
} else {
- write!(f, r##"
+ hwrite!(f, r##"
<text x="27" y="{}" fill="pink" stroke="red" {}
stroke-width="0.1" font-size="4">({})</text>"##,
nick_y, pointer, user,
)?;
}
}
- write!(f, r##"
+ hwrite!(f, r##"
</g>"##)?;
}
#[throws(IE)]
fn describe_html(&self, _gpc: &GPiece, _goccults: &GameOccults) -> Html {
- Html::lit("the chess clock")
+ Html::lit("the chess clock").into()
}
#[throws(InternalError)]
let state: &State = gpc.xdata_exp()?;
let for_users = || izip!(&USERS, &USERINFOS, &state.users).map(
- |(&user, userinfo, ust)| (user, userinfo, ust,
- userinfo.idchar.to_ascii_uppercase())
+ |(&user, userinfo, ust)| {
+ let upchar = userinfo.idchar.to_ascii_uppercase();
+ let upchar = IsHtmlFormatted(upchar);
+ (user, userinfo, ust, upchar)
+ }
);
for (user, userinfo, _ust, upchar) in for_users() {
kind: UoKind::Piece,
def_key: userinfo.idchar,
opname: format!("start-{}", userinfo.idchar),
- desc: Html(if state.current.is_none() {
- format!("Start, with player {}", &upchar)
+ desc: if state.current.is_none() {
+ hformat!("Start, with player {}", &upchar)
} else {
- format!("Make player {} current", &upchar)
- }),
+ hformat!("Make player {} current", &upchar)
+ },
wrc: WRC::Predictable,
});
}
kind: UoKind::Piece,
def_key: 'S',
opname: "stop".to_string(),
- desc: Html::lit("Stop"),
+ desc: Html::lit("Stop").into(),
wrc: WRC::Predictable,
});
}
kind: UoKind::Piece,
def_key: 'R',
opname: "reset".to_string(),
- desc: Html::lit("Reset"),
+ desc: Html::lit("Reset").into(),
wrc: WRC::Unpredictable,
});
}
if let Some(_gpl) = gs.players.get(ust.player) {
upd.push(UoDescription {
kind: UoKind::Piece,
- def_key: upchar,
+ def_key: upchar.0,
opname: format!("unclaim-{}", userinfo.idchar),
- desc: Html(format!("Clear player {}", &upchar)),
+ desc: hformat!("Clear player {}", &upchar),
wrc: WRC::Unpredictable,
});
} else {
upd.push(UoDescription {
kind: UoKind::Piece,
- def_key: upchar,
+ def_key: upchar.0,
opname: format!("claim-{}", userinfo.idchar),
- desc: Html(format!("Become player {}", &upchar)),
+ desc: hformat!("Become player {}", &upchar),
wrc: WRC::Unpredictable,
});
}
let log = log_did_to_piece(ioccults,&gs.occults, gpl, gpc, ipc, &did)
.unwrap_or_else(|e| {
error!("failed to log: {:?}", &e);
- vec![LogEntry { html: Html::lit("<failed to log>") }]
+ vec![LogEntry { html: "<failed to log>".to_html() }]
});
gpc.moveable = moveable;
use crate::prelude::*;
-pub const CORE_DESC: &str = "a play/pickup deck";
-pub const DISABLED_DESC: &str = "a play/pickup deck (disabled)";
-pub const COUNTING_DESC: &str = "a play pile (counting)";
-pub const ENABLED_DESC: &str = "a pickup deck (enabled)";
+pub const CORE_DESC : HtmlLit = Html::lit("a play/pickup deck");
+pub const DISABLED_DESC: HtmlLit = Html::lit("a play/pickup deck (disabled)");
+pub const COUNTING_DESC: HtmlLit = Html::lit("a play pile (counting)");
+pub const ENABLED_DESC : HtmlLit = Html::lit("a pickup deck (enabled)");
#[derive(Debug,Serialize,Deserialize)]
struct Deck {
label.svg(f,
&self.shape.outline,
self.shape.edges.get(0),
- &Html(count.to_string()))?;
+ &count.to_html())?;
}
}
}
#[throws(IE)]
fn describe_html(&self, gpc: &GPiece, goccults: &GameOccults) -> Html {
- Html::lit(
- match self.state(gpc, goccults)? {
- Disabled => DISABLED_DESC,
- Counting => ENABLED_DESC,
- Enabled => ENABLED_DESC,
- }
- )
+ match self.state(gpc, goccults)? {
+ Disabled => DISABLED_DESC,
+ Counting => ENABLED_DESC,
+ Enabled => ENABLED_DESC,
+ }.into()
}
delegate!{
kind: UoKind::Piece,
def_key: 'A',
opname: "activate".to_owned(),
- desc: Html::lit("Enable pickup deck"),
+ desc: Html::lit("Enable pickup deck").into(),
wrc: WRC::Unpredictable,
});
}
kind: UoKind::Piece,
def_key: 'C',
opname: "counting".to_owned(),
- desc: Html::lit("Make into counting play pile"),
+ desc: Html::lit("Make into counting play pile").into(),
wrc: WRC::Unpredictable,
});
}
kind: UoKind::Piece,
def_key: 'S',
opname: "deactivate".to_owned(),
- desc: Html::lit("Disable pickup deck"),
+ desc: Html::lit("Disable pickup deck").into(),
wrc: WRC::Unpredictable,
});
}
let gpc = gpieces.byid_mut(piece)?;
let gpl = gplayers.byid_mut(player)?;
- let nick = Html(htmlescape::encode_minimal(&gpl.nick));
+ let nick = gpl.nick.to_html();
dbgc!("ui op k entry", &opname);
let old_state = self.state(gpc, &goccults).map_err(err_via_response)?;
let (new_state, did) = match opname {
- "activate" => (Enabled, format!("enabled {}", CORE_DESC)),
- "counting" => (Counting, format!("set {} to counting", CORE_DESC)),
- "deactivate" => (Disabled, format!("disabled {}", CORE_DESC)),
+ "activate" => (Enabled, hformat!("enabled {}", CORE_DESC)),
+ "counting" => (Counting, hformat!("set {} to counting", CORE_DESC)),
+ "deactivate" => (Disabled, hformat!("disabled {}", CORE_DESC)),
_ => throw!(OE::BadOperation),
};
dbgc!("creating occ done", &xupdates);
}
- let log = vec![ LogEntry { html: Html(format!("{} {}", nick.0, did)) }];
+ let log = vec![ LogEntry { html: hformat!("{} {}", nick, did) }];
dbgc!("ui op k did main");
visible_slotmap_key!{ VisiblePieceId(b'.') }
-#[derive(Clone,Serialize,Deserialize,Hash,Eq,Ord,PartialEq,PartialOrd)]
-#[serde(transparent)]
-pub struct Html(pub String);
-
#[derive(Copy,Clone,Debug,Serialize,Deserialize,Eq,Ord,PartialEq,PartialOrd)]
#[serde(transparent)]
pub struct Timestamp(pub u64); /* time_t */
#[throws(fmt::Error)]
fn fmt(&self, f: &mut fmt::Formatter) { f.write_str(&self.0)? }
}
+ hformat_as_display!{ GoodItemName }
impl TryFrom<String> for GoodItemName {
type Error = LibraryLoadError;
}
}
-impl Html {
- // todo convert to display_as but I need to write display_as::typed::Is
- pub fn lit(s: &str) -> Self { Html(s.to_owned()) }
- pub fn from_txt(s: &str) -> Self {
- Html(htmlescape::encode_minimal(&s))
- }
-}
-
-impl Debug for Html {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- const MAX: usize = 23;
- if self.0.len() < MAX {
- write!(f, "<{}>", &self.0)
- } else {
- write!(f, "<{}>...", &self.0[0..MAX-3])
- }
- }
-}
-
// ---------- game state - rendering etc. ----------
impl GPiece {
impl GameState {
pub fn dummy() -> Self { GameState {
- table_colour: Html::lit("green"),
+ table_colour: Html::lit("green").into(),
table_size: PosC::new(300,200),
pieces: default(),
gen: Generation(0),
let front = self.log.front_mut().unwrap();
let front = &mut front.1;
let logent = LogEntry {
- html: Html::lit("[Earlier log entries expired]"),
+ html: Html::lit("[Earlier log entries expired]").into(),
};
*front = Arc::new(CommittedLogEntry { logent, when: front.when });
}
})
}).collect::<Vec<_>>();
let render = RenderContext { players };
- let html = Html(nwtemplates::render("player-info-pane.tera", &render)
- .context("render player info template")?);
+ let html = Html::from_html_string(
+ nwtemplates::render("player-info-pane.tera", &render)
+ .context("render player info template")?
+ );
html
}
}
}
}
-fn link_a_href<K:Display>(k: &K, v: &str) -> Html {
- let url = htmlescape::encode_minimal(v);
- Html(format!("<a href={url}>{kind}</a>", url=url, kind=k))
+fn link_a_href(k: &HtmlStr, v: &str) -> Html {
+ hformat!("<a href={}>{}</a>", v, k)
}
impl From<(LinkKind, &str)> for Html {
fn from((k, v): (LinkKind, &str)) -> Html {
- link_a_href(&k, v)
+ link_a_href(&k.to_html(), v)
}
}
let mut s = links.iter()
.filter_map(|(k,v)| {
let v = v.as_ref()?;
- Some(Html::from((k, v.as_str())).0)
+ Some(Html::from((k, v.as_str())))
})
.chain(iter::once(
- link_a_href(&"Shapelib", "/_/shapelib.html").0
+ link_a_href(Html::lit("Shapelib").into(), "/_/shapelib.html")
))
- .join(" ");
- if s.len() != 0 { s = format!("links: {}", s) }
- Html(s)
+ .collect::<Vec<Html>>()
+ .iter()
+ .hjoin(&Html::lit(" "));
+ if s.len() != 0 { s = hformat!("links: {}", s) }
+ s
}
}
use crate::prelude::*;
-pub const UNCLAIMED_DESC: &str = "a hand repository";
+pub const UNCLAIMED_DESC: HtmlLit = Html::lit("a hand repository");
#[derive(Debug,Clone,Serialize,Deserialize)]
struct MagicOwner {
if let Some(xdata) = xdata;
if let Some(owner) = &xdata.owner;
then { owner.desc.clone() }
- else { Html(UNCLAIMED_DESC.into()) }
+ else { UNCLAIMED_DESC.into() }
}
}
}
then { Some(owned) }
else { None }
};
- self.shape.svg_piece_raw(f, gpc.face, &mut |f: &mut String| {
+ self.shape.svg_piece_raw(f, gpc.face, &mut |f: &mut Html| {
if let Some(owned) = owned {
- write!(f, r##" stroke-dasharray="{}" "##, &owned.dasharray.0)?;
+ hwrite!(f, r##" stroke-dasharray="{}" "##, &owned.dasharray)?;
}
Ok(())
})?;
label.svg(f,
&self.shape.outline,
self.shape.edges.get(0),
- &Html(htmlescape::encode_minimal(&gpl.nick)))?;
+ &gpl.nick.to_html())?
}
}
}
kind: UoKind::Piece,
def_key: 'C',
opname: "deactivate".to_owned(),
- desc: Html::lit("Deactivate hand"),
+ desc: Html::lit("Deactivate hand").into(),
wrc: WRC::Unpredictable,
}}
else { UoDescription {
kind: UoKind::Piece,
def_key: 'C',
opname: "claim".to_owned(),
- desc: Html::lit("Claim this as your hand"),
+ desc: Html::lit("Claim this as your hand").into(),
wrc: WRC::Unpredictable,
}}
})
let dasharray = player_dasharray(gplayers, player);
let gpl = gplayers.byid_mut(player)?;
- let nick = Html(htmlescape::encode_minimal(&gpl.nick));
+ let nick = gpl.nick.to_html();
dbgc!("ui op k entry", &opname, &xdata);
{
("claim", false) => {
dbgc!("claiming");
- let new_desc = Html(format!("{}'s hand", &nick.0));
+ let new_desc = hformat!("{}'s hand", &nick);
let new_owner = Some(MagicOwner {
player,
dasharray,
region, piece, views)?;
dbgc!("creating occ done", &new_owner, &xupdates);
- (new_owner, xupdates, format!("claimed {}", &old_desc.0))
+ (new_owner, xupdates, hformat!("claimed {}", &old_desc))
}
("deactivate", true) => {
let xupdates =
to_recalculate, piece)
.map_err(|ie| ApiPieceOpError::ReportViaResponse(ie.into()))?;
- (None, xupdates, format!("deactivated {}", &old_desc.0))
+ (None, xupdates, hformat!("deactivated {}", &old_desc))
}
("claim", true) |
("deactivate", false) => {
}
};
- let log = vec![ LogEntry { html: Html(format!("{} {}", nick.0, did)) }];
+ let log = vec![ LogEntry { html: hformat!("{} {}", nick, did) }];
dbgc!("ui op k did main");
to_recalculate, piece,
|| (vanilla_wrc, vanilla_op, vanilla_log).into(),
vec![],
- |old, new, Html(show)| vec![ LogEntry { html: Html(format!(
+ |old, new, show| vec![ LogEntry { html: hformat!(
"{} {}",
- &who_by.0,
+ &who_by,
match (old, new) {
- (None, None) => format!("modified {} somehow", show),
- (Some(old), None) => format!("produced {} from {}", show, &old.0),
- (None, Some(new)) => format!("placed {} into {}", show, &new.0),
- (Some(old), Some(new)) => format!("moved {} from {} to {}",
- show, &old.0, &new.0),
- },
- ))}],
+ (None, None) => hformat!("modified {} somehow", show),
+ (Some(old), None) => hformat!("produced {} from {}", show, old),
+ (None, Some(new)) => hformat!("placed {} into {}", show, new),
+ (Some(old), Some(new)) => hformat!("moved {} from {} to {}",
+ show, old, new),
+ }
+ )}],
|puos, log| PieceUpdate {
wrc: WRC::Unpredictable,
ops: PieceUpdateOps::PerPlayer(puos),
pub struct $x(pub slotmap::KeyData);
impl_for_slotmap_key!($x($sep));
+ hformat_as_display!{$x}
}
}
#[macro_export]
pub mod error;
pub mod gamestate;
pub mod global;
+pub mod html;
pub mod hand;
pub mod hidden;
pub mod keydata;
#[derive(Clone,Debug)]
#[derive(Serialize,Deserialize)]
#[serde(transparent)]
-pub struct VisibleAngleTransform(String);
+pub struct VisibleAngleTransform(Html);
#[derive(Debug,Clone)]
pub struct PieceRenderInstructions {
impl VisiblePieceAngle {
pub fn to_transform(self) -> VisibleAngleTransform {
- VisibleAngleTransform(base_misc::raw_angle_transform(
- self.to_compass().into()
- ))
+ VisibleAngleTransform(Html::from_html_string(
+ base_misc::raw_angle_transform(
+ self.to_compass().into()
+ )))
}
pub fn to_compass(self) -> CompassAngle {
self.describe_fallible(ioccults, goccults, gpc, ipc)
.unwrap_or_else(|e| {
error!("error describing piece: {:?}", e);
- Html::lit("<internal error describing piece>")
+ "<internal error describing piece>".to_html()
})
}
let transform = angle.to_transform();
- let mut defs = Html(String::new());
- write!(&mut defs.0,
+ let mut defs = Html::new();
+ hwrite!(&mut defs,
r##"<g id="piece{}" transform="{}" data-dragraise="{}">"##,
pri.vpid, &transform.0, dragraise)?;
},
};
- write!(&mut defs.0, r##"</g>"##)?;
- write!(&mut defs.0,
+ hwrite!(&mut defs, r##"</g>"##)?;
+ hwrite!(&mut defs,
r##"<path id="surround{}" d="{}"/>"##,
- pri.vpid, o.surround_path()?.0)?;
+ pri.vpid, o.surround_path()?)?;
defs
}
kind: UoKind::Global,
def_key: 'f'.into(),
opname: "flip".to_string(),
- desc: Html::lit("flip"),
+ desc: Html::lit("flip").into(),
})
}
ipc.show(y).add_ui_operations(&mut out, gs, gpc)?;
}
#[throws(SvgE)]
-pub fn svg_rescale_path(input: &Html, scale: f64) -> Html {
+pub fn svg_rescale_path(input: &HtmlStr, scale: f64) -> Html {
type BM = u64;
type BI = u32;
#[derive(Debug,Copy,Clone)]
let mut map = ALWAYS_MAP;
let mut first = iter::once(());
- for w in input.0.split_ascii_whitespace() {
+ for w in input.as_html_str().split_ascii_whitespace() {
if first.next().is_none() { write!(&mut out, " ")?; }
match w {
"L" | "l" | "M" | "m" |
}
trace!("rescaled by {}: {:?} as {:?}", scale, input, &out);
- Html(out)
+ Html::from_html_string(out)
}
#[throws(SvgE)]
a 1 1 0 1 0 0 2 z"
);
let scale = diam * 0.5;
- let path = svg_rescale_path(&unit_path, scale)?;
+ let path = svg_rescale_path(unit_path.into(), scale)?;
path
}
#[throws(SvgE)]
pub fn svg_rectangle_path(PosC{coords: [x,y]}: PosC<f64>) -> Html {
- Html(format!("M {} {} h {} v {} h {} z",
- -x*0.5, -y*0.5, x, y, -x))
+ hformat!("M {} {} h {} v {} h {} z",
+ -x*0.5, -y*0.5, x, y, -x)
}
#[dyn_upcast]
_gs: &GameState, _vpid: VisiblePieceId) {
self.svg_piece_raw(f, gpc.face, &mut |_|Ok(()))?;
}
- #[throws(IE)]
- fn describe_html(&self, gpc: &GPiece, _goccults: &GameOccults) -> Html {
- Html(if_chain! {
+// #[throws(IE)]
+ fn describe_html(&self, gpc: &GPiece, _goccults: &GameOccults)
+// -> Html
+-> Result<Html, IE>
+ {
+Ok::<_,IE>(
+ if_chain! {
if let face = gpc.face;
if let Some(colour) = self.colours.get(face);
- then { format!("a {} {}", colour.0, self.desc.0) }
- else { format!("a {}", self.desc.0) }
- })
+ then { hformat!("a {} {}", colour, self.desc) }
+ else { hformat!("a {}", self.desc) }
+ }
+)
}
fn nfaces(&self) -> RawFaceId {
self.count_faces().try_into().unwrap()
def_colour: Option<&Colour>,
text: &Html) {
let colour = {
- if let Some(c) = &self.colour { &c.0 }
- else if let Some(c) = def_colour { &c.0 }
- else { "black" }
+ if let Some(c) = &self.colour { c.borrow() }
+ else if let Some(c) = def_colour { c.borrow() }
+ else { Html::lit("black").into() }
};
let fontsz = 4.;
let PosC{ coords: [x,y] } = {
*y += 0.5 * fontsz;
pos
};
- write!(f.0,
- r##"<text x="{}" y="{}" font-size="{}" fill="{}">{}</text>"##,
- x, y, fontsz, colour, &text.0
+ hwrite!(f,
+ r##"<text x="{}" y="{}" font-size="{}" fill="{}">{}</text>"##,
+ x, y, fontsz, colour, &text
)?;
}
}
#[throws(IE)]
pub fn svg_piece_raw(
&self, f: &mut Html, face: FaceId,
- stroke_attrs_hook: &mut dyn FnMut(&mut String) -> Result<(),IE>,
+ stroke_attrs_hook: &mut dyn FnMut(&mut Html) -> Result<(),IE>,
) {
- let f = &mut f.0;
- let ef = |f: &mut String, cmap: &ColourMap, attrname: &str, otherwise| {
+ let ef = |f: &mut Html, cmap: &ColourMap, attrname: &str, otherwise| {
if let Some(colour) = cmap.get(face) {
- write!(f, r##" {}="{}""##, attrname, colour.0)
+ hwrite!(f, r##" {}="{}""##, attrname, colour)
} else {
- write!(f, "{}", otherwise)
+ hwrite!(f, "{}", otherwise)
}
};
let path = self.outline_path(1.0)?;
if self.colours.len() == 0 {
- write!(f,
+ hwrite!(f,
r##"<path fill="none" \
stroke-width="{}" stroke="transparent" d="{}"/>"##,
INVISIBLE_EDGE_SENSITIVE,
- &path.0)?;
+ &path)?;
}
- write!(f, r##"<path"##)?;
+ hwrite!(f, r##"<path"##)?;
ef(f, &self.colours, "fill", r##" fill="none""##)?;
if self.edges.len() != 0 {
- write!(f, r##" stroke-width="{}""##, &self.edge_width)?;
+ hwrite!(f, r##" stroke-width="{}""##, &self.edge_width)?;
}
stroke_attrs_hook(f)?;
ef(f, &self.edges, "stroke", "")?;
- write!(f, r##" d="{}"/>"##, &path.0)?;
+ hwrite!(f, r##" d="{}"/>"##, &path)?;
}
}
fn load_raw(&self) -> (SimpleShape, &SimpleCommon) {
let outline = CircleShape { diam: self.diam as f64 };
(SimpleShape::new(
- Html::lit("disc"),
+ Html::lit("disc").into(),
outline.into(),
"simple-disc",
&self.common,
let desc = Html::lit(
if outline.xy.x() == outline.xy.y()
{ "square" } else { "rectangle" }
- );
+ ).into();
(SimpleShape::new(
desc,
outline.into(),
pub use crate::{deref_to_field, deref_to_field_mut};
pub use crate::ensure_eq;
pub use crate::from_instance_lock_error;
+pub use crate::{hformat, hformat_as_display, hwrite};
pub use crate::matches_doesnot;
pub use crate::trace_dbg;
pub use crate::gamestate::*;
pub use crate::global::*;
pub use crate::hidden::*;
+pub use crate::html::*;
pub use crate::keydata::*;
pub use crate::mgmtchannel::*;
pub use crate::nwtemplates;
#[cfg(doc)] pub r_file_spec: String,
#[cfg(not(doc))] pub r_file_spec: (),
- /// HTML desscription. (Shown hn the game log, for example.)
- pub desc: Html,
+ /// Desscription. (Shown hn the game log, for example.)
+ /// Will be HTML-escaped.
+ pub desc: String,
}
#[cfg(doc)]
impl ItemEnquiryData {
pub fn line_for_list(&self) -> String {
- format!("{:20} {}", self.itemname.as_str(), self.f0desc.0)
+ format!("{:20} {}", self.itemname, self.f0desc.as_html_str())
}
}
#[throws(IE)]
fn write_svgd(&self, f: &mut Html, svgd: &Html) {
- write!(&mut f.0,
+ hwrite!(f,
r##"<g transform="scale({} {}) translate({} {})">{}</g>"##,
self.scale[0], self.scale[1], -self.centre[0], -self.centre[1],
- svgd.0)?;
+ svgd)?;
}
}
SpE::InternalError(m.to_string())
})?;
- Html(svg_data)
+ Html::from_html_string(svg_data)
}
#[throws(SpecError)]
if ! group.d.colours.contains_key(colour.0.as_str()) {
throw!(LLE::OccultationColourMissing(colour.0.clone()));
}
- let colour: Colour = colour.try_into()?;
let item_name = subst(item_name.as_str(), "_c", &colour.0)?;
+ let desc = subst(&fe.desc, "_colour", "")?.to_html();
OccData::Internal(Arc::new(OccData_Internal {
item_name: Arc::new(item_name.try_into()?),
- desc: Html(subst(&fe.desc.0, "_colour", "")?),
outline: outline.clone(),
xform: FaceTransform::from_group(&group.d)?,
svgd: default(),
+ desc,
}))
},
Some(OccultationMethod::ByBack { ilk }) => {
},
};
- let mut add1 = |item_name: &GoodItemName, desc: Html| {
+ let mut add1 = |item_name: &GoodItemName, desc: &str| {
let desc = if let Some(desc_template) = &group.d.desc_template {
- Html(subst(desc_template, "_desc", &desc.0)?)
+ subst(desc_template, "_desc", &desc)?.to_html()
} else {
- desc
+ desc.to_html()
};
let idata = ItemData {
group: group.clone(),
};
if group.d.colours.is_empty() {
- add1(&item_name, fe.desc.clone())?;
+ add1(&item_name, &fe.desc.clone())?;
} else {
for (colour, recolourdata) in &group.d.colours {
let t_item_name = subst(item_name.as_str(), "_c", &recolourdata.abbrev)?;
- let t_desc = Html(subst(&fe.desc.0, "_colour", colour)?);
- add1(&t_item_name.try_into()?, t_desc)?;
+ let t_desc = subst(&fe.desc, "_colour", colour)?;
+ add1(&t_item_name.try_into()?, &t_desc)?;
}
}
};
let item_spec = n()?;
let _r_file_spec = n()?;
- let desc = Html(remain.to_owned());
- o.push(FileData{ item_spec, r_file_spec: (), desc });
+ let desc = remain.to_owned();
+ o.push(FileData{ item_spec, r_file_spec: (), desc });
}
Ok(FileList(o))
}
use crate::accounts::AccountName;
use crate::error::UnsupportedColourSpec;
use crate::gamestate::PieceSpec;
+use crate::hformat_as_display;
use crate::prelude::default;
pub use implementation::PlayerAccessSpec;
Voice,
Info,
}
+hformat_as_display!{LinkKind}
//---------- player accesses, should perhaps be in commands.rs ----------
-> Result<AccessTokenReport, TDE>;
fn describe_html(&self) -> Html {
let inner = Html::from_txt(&format!("{:?}", self));
- Html(format!("<code>{}</code>", inner.0))
+ hformat!("<code>{}</code>", inner)
}
}
if !RE.is_match(s) {
throw!(UnsupportedColourSpec);
}
- Html(spec.0.clone())
+ Html::from_html_string(spec.0.clone())
}
}
}
let spc = dasharray.pop();
assert_eq!(spc,Some(' '));
- Html(dasharray)
+ Html::from_html_string(dasharray)
}
pub fn player_dasharray(gplayers: &GPlayers, player: PlayerId) -> Html {
}
impl JsonLen for Html {
- fn json_len(&self) -> usize { self.0.as_bytes().len() }
+ fn json_len(&self) -> usize { self.as_html_str().as_bytes().len() }
}
// ---------- piece updates ----------
gpc: &GPiece, ipc: &IPiece, did: &str)
-> (Vec<LogEntry>, Option<Html>)
{
- let who_by = Html(htmlescape::encode_minimal(&by_gpl.nick));
+ let who_by = by_gpl.nick.to_html();
let y = gpc.fully_visible_to_everyone();
let desc = (||{
Ok::<_,IE>(match ipc.show_or_instead(ioccults, y)? {
})
})().unwrap_or_else(|e|{
error!("failed to format during logging: {:?}", e);
- Html::lit("<internal error>")
+ Html::lit("<internal error>").into()
});
- let log = vec![ LogEntry { html: Html(format!(
+ let log = vec![ LogEntry { html: hformat!(
"{} {} {}",
- &who_by.0,
+ who_by,
did,
- desc.0,
- ))}];
+ desc,
+ )}];
(log, Some(who_by))
}
ims.json_len(player)
}
Log(logent) => {
- logent.logent.html.0.as_bytes().len() * 28
+ logent.logent.html.json_len() * 28
}
AddPlayer {
player:_,
data: DataLoadPlayer { dasharray, nick, },
new_info_pane,
} => {
- dasharray.0.as_bytes().len() +
- nick .0.as_bytes().len() + 100
- + new_info_pane.0.len()
+ dasharray.json_len() +
+ nick .json_len() + 100
+ + new_info_pane.json_len()
}
RemovePlayer { player:_, new_info_pane } => {
- new_info_pane.0.len() + 100
+ new_info_pane.json_len() + 100
}
SetTableColour(colour) => {
- colour.0.as_bytes().len() + 50
+ colour.json_len() + 50
}
SetLinks(links) => {
links.iter().filter_map(
let gplayers = &ig.gs.players;
let dasharray = player_dasharray(gplayers, player);
let nick = gplayers.get(player).map(|gpl| gpl.nick.as_str())
- .unwrap_or("<unknown-player>");
- let nick = Html(htmlescape::encode_minimal(&nick));
+ .unwrap_or("<unknown-player>")
+ .to_html();
DataLoadPlayer {
dasharray,
nick,
let (player,_) = player.get_idx_version();
let player: usize = player.try_into().unwrap();
let player = player.try_into().unwrap();
- let dasharray = player_num_dasharray(player).0;
- dasharray
+ let dasharray = player_num_dasharray(player);
+ dasharray.into_html_string()
}
impl Ctx {