Make the naming scheme fully user-editable, with the user's preferred format as default

- ExpressionFormat::compile_scriptlet now falls back to treating a {token} as a
  literal multi-word binding key when it's neither a valid Rhai identifier nor
  valid Rhai script, but still looks like a plain human-typed field name (only
  letters/digits/underscores/spaces). This is what lets `{show name}` work
  without anyone needing to know Rhai, while real Rhai script (even containing
  spaces) still takes priority and genuine syntax errors still surface.
- New default naming scheme app-wide: `{show name} - {season number}x
  {episode number} - {episode name}` (previously the terser {n} - {s00e00} -
  {t} form). Match/Fetch Data auto-upgrade targets updated to match, and
  sample items carry both the short FileBot-style keys and the new
  human-readable ones side by side.
- Naming scheme editor UI rewritten: explains the field is fully editable,
  lists available fields grouped by when they become available (always /
  after Match / after Fetch Data), and clarifies Rhai script is also
  supported for anyone who wants it.
- 3 new unit tests for the plain-field-name fallback (multi-word lookup
  works, real Rhai still takes priority, genuine syntax errors still error).
This commit is contained in:
Renamr Scaffold
2026-08-29 03:15:21 +00:00
parent d1fc4039a7
commit f89589bc88
7 changed files with 240 additions and 22 deletions
@@ -64,3 +64,36 @@ fn syntax_error_is_reported_with_the_offending_expression() {
let message = err.to_string();
assert!(message.contains("syntax error"), "message was: {message}");
}
#[test]
fn multi_word_plain_field_names_are_treated_as_literal_binding_keys() {
// "show name" etc. aren't valid Rhai (two bare identifiers with no operator between
// them), so this only works because compile_scriptlet falls back to a literal key
// lookup when a token looks like a plain human-typed field name rather than code.
let fmt = ExpressionFormat::compile("{show name} - {season number}x{episode number} - {episode name}").unwrap();
let bindings = string_bindings([
("show name", "Reacher"),
("season number", "1"),
("episode number", "1"),
("episode name", "Welcome to Margrave"),
]);
assert_eq!(fmt.format(&bindings).unwrap(), "Reacher - 1x1 - Welcome to Margrave");
}
#[test]
fn rhai_expressions_still_take_priority_over_plain_field_name_fallback() {
// Contains spaces too, but it's valid Rhai (string concatenation) - should compile
// and run as a script, never falling through to the plain-field-name path.
let fmt = ExpressionFormat::compile(r#"{n + " " + t}"#).unwrap();
let bindings = string_bindings([("n", "Breaking Bad"), ("t", "Ozymandias")]);
assert_eq!(fmt.format(&bindings).unwrap(), "Breaking Bad Ozymandias");
}
#[test]
fn genuinely_invalid_syntax_with_spaces_still_errors() {
// Has spaces like a plain field name might, but also punctuation that no field name
// would ever contain - should still be reported as a real syntax error, not
// silently treated as a (wrong) literal key.
let err = ExpressionFormat::compile("{show name (}").unwrap_err();
assert!(err.to_string().contains("syntax error"), "message was: {err}");
}