Skip to content

Commit

Permalink
Split format plugin (#193)
Browse files Browse the repository at this point in the history
* documentation for split format plugin

* implement split format and fix style bugs

* clean up

* fix cancel not working
  • Loading branch information
Pistonight committed Feb 17, 2024
1 parent 987b097 commit 875e185
Show file tree
Hide file tree
Showing 16 changed files with 327 additions and 74 deletions.
3 changes: 1 addition & 2 deletions compiler-core/src/plugin/builtin/botw_unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,8 +396,7 @@ fn estimate_time(text: &DocRichText) -> u32 {
impl PluginRuntime for BotwAbilityUnstablePlugin {
fn on_after_compile(&mut self, comp_doc: &mut CompDoc) -> PluginResult<()> {
operation::for_each_line!(line in comp_doc {
self.process_line(&mut line);
line
self.process_line(line);
});
Ok(())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl PluginRuntime for ExportLiveSplitPlugin {
icon: ExportIcon::Data,
extension: Some("lss".to_string()),
export_id: None,
example_config: Some(include_str!("./livesplit.yaml").to_string()),
example_config: Some(include_str!("./export_livesplit.yaml").to_string()),
learn_more: Some("/docs/plugin/export-livesplit#export-livesplit".to_string()),
};
Ok(Some(vec![metadata]))
Expand Down
1 change: 0 additions & 1 deletion compiler-core/src/plugin/builtin/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ impl PluginRuntime for LinkPlugin {
if let Some(t) = line.counter_text.as_mut() {
transform_link_tag(t);
}
line
});

Ok(())
Expand Down
11 changes: 8 additions & 3 deletions compiler-core/src/plugin/builtin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,21 @@ use crate::pack::CompileContext;
use super::{PluginResult, PluginRuntime};

mod botw_unstable;
mod export_livesplit;
mod link;
mod livesplit;
mod metrics;
mod split_format;
mod variables;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum BuiltInPlugin {
BotwAbilityUnstable,
BotwAbilityUnstable, // TODO #24: remove this
#[serde(rename = "export-livesplit")]
ExportLiveSplit,
Link,
Metrics,
SplitFormat,
Variables,
}

Expand All @@ -36,12 +38,15 @@ impl BuiltInPlugin {
BuiltInPlugin::BotwAbilityUnstable => Ok(Box::new(
botw_unstable::BotwAbilityUnstablePlugin::from_props(props),
)),
BuiltInPlugin::ExportLiveSplit => Ok(Box::new(livesplit::ExportLiveSplitPlugin)),
BuiltInPlugin::ExportLiveSplit => Ok(Box::new(export_livesplit::ExportLiveSplitPlugin)),
BuiltInPlugin::Link => Ok(Box::new(link::LinkPlugin)),
BuiltInPlugin::Metrics => Ok(Box::new(metrics::MetricsPlugin::from_props(
props,
&ctx.start_time,
))),
BuiltInPlugin::SplitFormat => {
Ok(Box::new(split_format::SplitFormatPlugin::from_props(props)))
}
BuiltInPlugin::Variables => Ok(Box::new(variables::VariablesPlugin::from_props(props))),
}
}
Expand Down
143 changes: 143 additions & 0 deletions compiler-core/src/plugin/builtin/split_format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
//! Split format plugin
//!
//! Automatically set the `split-name` property based on the split type

use std::borrow::Cow;
use std::collections::BTreeMap;

use serde_json::Value;

use crate::comp::{CompDoc, CompLine};
use crate::json::Coerce;
use crate::lang::{self, DocRichText};
use crate::plugin::{operation, PluginResult, PluginRuntime};

pub struct SplitFormatPlugin {
formats: BTreeMap<String, DocRichText>,
}

impl SplitFormatPlugin {
pub fn from_props(props: &Value) -> Self {
let mut formats = BTreeMap::new();
if let Some(props) = props.as_object() {
for (k, v) in props {
formats.insert(k.clone(), lang::parse_rich(&v.coerce_to_string()));
}
}
Self { formats }
}
}

impl PluginRuntime for SplitFormatPlugin {
fn get_id(&self) -> Cow<'static, str> {
Cow::Owned(super::BuiltInPlugin::SplitFormat.id())
}
fn on_after_compile(&mut self, comp_doc: &mut CompDoc) -> PluginResult<()> {
let mut tag_to_format = BTreeMap::new();
for (tag_name, tag) in comp_doc.config.tags.iter() {
if let Some(split_type) = &tag.split_type {
if let Some(format) = self.formats.get(split_type) {
tag_to_format.insert(tag_name.clone(), format);
}
}
}
operation::for_each_line!(line in comp_doc {
let mut format = None;
if let Some(counter) = &line.counter_text {
if let Some(tag) = &counter.tag {
format = tag_to_format.get(tag);
}
// this is to get .var(type) to work
if format.is_none() {
format = tag_to_format.get(&counter.text);
}
}
if let Some(format) = format {
let mut format = (*format).clone();
transform_format(&mut format, line);
line.split_name = Some(format);
}
});

Ok(())
}
}

/// Transforms the prop tag inside the format
fn transform_format(format: &mut DocRichText, line: &CompLine) {
for block in &mut format.0 {
let tag = match &block.tag {
Some(tag) => tag,
None => continue,
};
if tag != "prop" {
continue;
}
match block.text.as_ref() {
"text" => {
block.text = line.text.to_string();
}
"comment" => {
block.text = line.secondary_text.to_string();
}
"counter" => {
block.text = line
.counter_text
.as_ref()
.map(|x| x.text.to_string())
.unwrap_or_default();
}
_ => {}
}
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_no_transform() {
let line = CompLine::default();
let mut format = lang::parse_rich("Test no transform");
let expected = format.clone();
transform_format(&mut format, &line);
assert_eq!(format, expected);
}

#[test]
fn test_transform_text() {
let line = CompLine {
text: lang::parse_rich("Test Text"),
..Default::default()
};
let mut format = lang::parse_rich("Test .prop(text)");
let expected = lang::parse_rich("Test .prop(Test Text)");
transform_format(&mut format, &line);
assert_eq!(format, expected);
}

#[test]
fn test_transform_comment() {
let line = CompLine {
secondary_text: lang::parse_rich("Test .test(Text)"),
..Default::default()
};
let mut format = lang::parse_rich("Test .prop(comment)");
let expected = lang::parse_rich("Test .prop(Test Text)");
transform_format(&mut format, &line);
assert_eq!(format, expected);
}

#[test]
fn test_transform_counter() {
let line = CompLine {
counter_text: lang::parse_rich(".test(Test Text)").0.into_iter().next(),
..Default::default()
};
let mut format = lang::parse_rich("Test .prop(counter)");
let expected = lang::parse_rich("Test .prop(Test Text)");
transform_format(&mut format, &line);
assert_eq!(format, expected);
}
}
1 change: 0 additions & 1 deletion compiler-core/src/plugin/builtin/variables/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,6 @@ impl PluginRuntime for VariablesPlugin {
line.properties.insert(prop::VALS.to_string(), self.get_vals());
}
self.clear_temporary();
line
});

Ok(())
Expand Down
6 changes: 2 additions & 4 deletions compiler-core/src/plugin/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
macro_rules! for_each_line {
($line:ident in $comp_doc:ident $fun:block) => {
for section in $comp_doc.route.iter_mut() {
let lines = std::mem::take(&mut section.lines);
#[allow(unused_mut)]
for mut $line in lines.into_iter() {
let l = $fun;
section.lines.push(l);
for $line in section.lines.iter_mut() {
$fun;
}
}
};
Expand Down
1 change: 1 addition & 0 deletions docs/src/.vitepress/nav/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const pluginsSideBar = {
items: [
{ text: "Link", link: "/plugin/link" },
{ text: "Variables", link: "/plugin/variables" },
{ text: "Split Format", link: "/plugin/split-format" },
// { text: "Compatibility", link: "/plugin/compat" },
],
},
Expand Down
59 changes: 59 additions & 0 deletions docs/src/plugin/split-format.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Split Format
The `split-format` plugin automatically sets the [`split-name`](../route/counter-and-splits#format-split-names) property for lines
based on the split type of that route (set by the `counter` property), with
a configurable format.

Add the plugin with
```yaml
config:
- plugins:
- use: split-format
with:
# configure format here
```

## Configuration
### Use the correct name for split types
You can configure one format per split type based on the [display name of the type
configured on the counter tag](../route/counter-and-splits#splitting).

For example, with this setup:
```yaml
config:
- tags:
my-counter:
split-type: My Counters

route:
- Example Section:
- Example Line:
counter: .my-counter()
```
The name to use is "My Counters", not "my-counter".
:::tip
The split-type is also what's shown in the settings dialog. Check there if you don't know!
:::
### Configure formats
Use the split type names as keys and the split format as the value in the configuration.
For example:
```yaml
config:
- plugins:
- use: split-format
with:
My Counters: Counter
Shrines: "[.var(pad03:counter-shrine)] .prop(text)"
```
The `prop` tag can be used to access properties of the line:
- `.prop(text)` becomes the primary text
- `.prop(comment)` becomes the secondary text
- `.prop(counter)` becomes the counter text

Note that tags cannot be nested - `.var(.prop(text))` is not supported!

:::warning
If `.var` is used inside the split formats, the `split-format` plugin needs to
be BEFORE the `variables` plugin in the `plugins` list!
:::
43 changes: 41 additions & 2 deletions docs/src/route/counter-and-splits.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,46 @@ config:

Now, go to the split settings and click on `Reset`. You should see the `My Counters` type getting checked by default.

## Export Split Files
See [Export](../export.md)

## Format Split Names
:::info
Not implemented yet. Tracked by [TODO #21](https://github.com/Pistonite/celer/issues/21)
:::tip
This section explains how split names are set manually with the `split-name` property.
Most of the time, it's easier to use the [`split-format`](../plugin/split-format.md) plugin
to set this property automatically based on the split type.
:::
By default, the split names in the exported split files are the same as the primary text of the line.
You can change it with the `split-name` property.

```yaml
route:
- Example Section:
# This split will have name "Split 1"
- Split 1:
counter: my-counter
# This split will have name "Split 2"
- Some text:
counter: my-counter
split-name: Split 2
```

The [`variables`](../plugin/variables.md) plugin can be used to interpolate variables into the split name

```yaml
config:
- plugins:
- use: variables
route:
- Example Section:
# This split will have name "Split 1"
- Split 1:
counter: my-counter
vars:
x: 1
# This split will have name "x is 1"
- Some text:
counter: my-counter
split-name: x is .var(x)
```
3 changes: 2 additions & 1 deletion web-client/src/core/kernel/AlertMgr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { AlertExtraAction, ModifyAlertActionPayload } from "core/stage";
import { AppDispatcher, viewActions } from "core/store";
import { Result, allocErr, allocOk } from "low/utils";
import { Result, allocErr, allocOk, console } from "low/utils";

/// Options for showing a simple alert
export type AlertOptions<TExtra extends AlertExtraAction[]> = {
Expand Down Expand Up @@ -128,6 +128,7 @@ export class AlertMgr {
// when alert is notified through user action,
// it means cancel
cancelled = true;
console.info("user cancelled the operation");
resolve(allocErr(false));
}, component);
this.store.dispatch(
Expand Down
3 changes: 2 additions & 1 deletion web-client/src/ui/doc/components/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,12 @@ export const useDocStyles = makeStyles({
[DocNoteContainerClass.className]: {
display: "none", // hidden by default
transitionDuration: "0.1s",
// left: 0,
left: 0,
right: 0,
boxSizing: "border-box",

"@container (max-width: 100px)": {
left: "unset",
width: "100%", // need this so 100% can be propagated to children
[`& .${DocNoteBlockClass.className}`]: {
height: "32px",
Expand Down
Loading

0 comments on commit 875e185

Please sign in to comment.