Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::inspect::TweakStore Class Reference

In-memory record of inspector direct-manipulation edits ("tweaks"), keyed by stable_anchor_id + dotted property path (e.g. More...

#include <tweak_store.hpp>

Classes

struct  Record
 A single tweak record returned by list_tweaks(). More...
struct  BatchEntry
 One (property_path, value) pair within a batched apply. More...
struct  DiskResult
 Outcome of a disk operation. More...
struct  DriftedTweak
 One drifted tweak — a stored edit that no longer maps cleanly to the current design. More...
struct  DriftReport
 Three-way classification of every stored tweak against a design. More...
struct  DesignSnapshot
 A design snapshot the drift logic diffs tweaks against. More...

Public Types

enum class  DriftReason { anchor_not_found , property_not_found }
 Why a tweak failed to apply cleanly. More...
using BypassValue = std::variant<bool, std::vector<std::string>>
 Bypass overlay value — matches the TS true | string[] shape.

Public Member Functions

 TweakStore ()=default
std::size_t apply_tweak (std::string_view anchor_id, std::string_view property_path, choc::value::Value value, std::string_view source={})
 Record an edit.
std::size_t apply_tweaks_batch (std::string_view anchor_id, std::vector< BatchEntry > entries, std::string_view source={})
 Apply several tweaks under one anchor as a SINGLE atomic unit.
bool remove_tweak (std::string_view anchor_id, std::string_view property_path)
 Remove a single (anchor_id, property_path) entry.
std::size_t remove_anchor (std::string_view anchor_id)
 Remove all entries for an anchor.
void clear ()
 Clear the entire table (tweaks + bypass overlay + lock set).
void set_bypass (std::string_view anchor_id, BypassValue value)
 Set the bypass state for an anchor.
void clear_bypass (std::string_view anchor_id)
 Convenience: clear the bypass for an anchor (equivalent to set_bypass(id, false)).
void set_locked (std::string_view anchor_id, bool locked)
 Set the lock state for an anchor.
void clear_lock (std::string_view anchor_id)
 Convenience: clear the lock for an anchor (equivalent to set_locked(id, false)).
std::size_t count () const
 Total number of (anchor, property) entries.
std::vector< Record > list_tweaks () const
 Return every record in the store's stable order.
std::optional< choc::value::Value > lookup (std::string_view anchor_id, std::string_view property_path) const
 Look up a specific (anchor_id, property_path).
bool is_bypassed (std::string_view anchor_id, std::string_view property_path) const
 Whether a specific (anchor_id, property_path) is currently bypassed (either whole-anchor or path-specific).
std::optional< BypassValue > bypass_for (std::string_view anchor_id) const
 Current bypass state for an anchor.
std::vector< std::string > bypassed_anchors () const
 Return every anchor id that currently has a bypass entry, regardless of whether it also has tweak records.
bool is_locked (std::string_view anchor_id) const
 Whether anchor_id is currently locked.
std::vector< std::string > locked_anchors () const
 Return every anchor id that currently carries a lock, in unspecified order.
DiskResult load_from_disk (std::string_view path={})
 Replace the in-memory state with the contents of path.
DiskResult save_to_disk (std::string_view path={}) const
 Atomically write the current in-memory state to path.
void set_auto_save (bool enabled, std::string_view path={})
 Enable / disable post-mutation auto-save.
bool auto_save_enabled () const
 Whether auto-save is currently armed.
std::string auto_save_path () const
 The path auto-save flushes to (empty if auto-save is off and no explicit path has ever been set).
std::string to_json () const
 Serialize the current state to a JSON string in the on-disk schema.
DiskResult from_json (std::string_view json)
 Replace state from an in-memory JSON string.
DriftReport diff (const DesignSnapshot &design) const
 Classify every stored tweak against design.
DriftReport diff (const std::vector< std::string > &live_anchors) const
 Convenience: classify against a flat anchor list (anchor-only matching — no property-level drift).
std::vector< DriftedTweak > find_drifted (const DesignSnapshot &design) const
 Return only the orphaned + drifted tweaks for design — the subset the inspector drift drawer renders.
std::vector< DriftedTweak > find_drifted (const std::vector< std::string > &live_anchors) const
 Convenience overload taking a flat anchor list.

Static Public Member Functions

static std::string default_tweaks_path ()
 Resolve the default pulp-tweaks.json location:
static const char * drift_reason_str (DriftReason reason)
 Stringify a DriftReason for JSON / human output.
static std::string drift_report_to_json (const DriftReport &report)
 Render a DriftReport as a JSON string (used by pulp tweaks diff --json and the protocol layer).

Static Public Attributes

static constexpr int kSchemaVersion = 1
 On-disk schema version. Bumped if/when we ever break the format.

Detailed Description

In-memory record of inspector direct-manipulation edits ("tweaks"), keyed by stable_anchor_id + dotted property path (e.g.

"paint.backgroundColor", "layout.padding").

Thread-safety: external mutex; all public methods take the same internal mutex so the inspector can safely receive concurrent applyTweak / listTweaks calls from multiple connected clients.

Member Typedef Documentation

◆ BypassValue

using pulp::inspect::TweakStore::BypassValue = std::variant<bool, std::vector<std::string>>

Bypass overlay value — matches the TS true | string[] shape.

bool=true bypasses every tweak under an anchor; a non-empty vector bypasses only the listed dotted paths.

Member Enumeration Documentation

◆ DriftReason

Why a tweak failed to apply cleanly.

Enumerator
anchor_not_found 

No live view carries this anchor_id.

property_not_found 

Anchor resolves but the design no longer exposes this property path.

Constructor & Destructor Documentation

◆ TweakStore()

pulp::inspect::TweakStore::TweakStore ( )
default

Member Function Documentation

◆ apply_tweak()

std::size_t pulp::inspect::TweakStore::apply_tweak ( std::string_view anchor_id,
std::string_view property_path,
choc::value::Value value,
std::string_view source = {} )

Record an edit.

Overwrites any prior value at the same (anchor_id, property_path). Returns the post-write tweak count.

◆ apply_tweaks_batch()

std::size_t pulp::inspect::TweakStore::apply_tweaks_batch ( std::string_view anchor_id,
std::vector< BatchEntry > entries,
std::string_view source = {} )

Apply several tweaks under one anchor as a SINGLE atomic unit.

Motivation: the drag-to-move gesture writes three tweaks — layout.position, layout.left, layout.top — and apply_tweak() auto-saves to disk after EVERY call, so three separate calls flush the file three times and a crash mid-sequence can persist a partial move (e.g. left/top without position). Worse, that partial state is NOT a no-op: Yoga applies insets to relative nodes too, so a still-relative node with stray left/top shifts in flow.

apply_tweaks_batch takes the internal lock once, mutates every (anchor, path) key, and triggers at most ONE auto-save flush after all keys are written — so the on-disk state is all-or-nothing. Returns the post-write total tweak count. A no-op (returns the current count) when entries is empty.

◆ auto_save_enabled()

bool pulp::inspect::TweakStore::auto_save_enabled ( ) const

Whether auto-save is currently armed.

◆ auto_save_path()

std::string pulp::inspect::TweakStore::auto_save_path ( ) const

The path auto-save flushes to (empty if auto-save is off and no explicit path has ever been set).

◆ bypass_for()

std::optional< BypassValue > pulp::inspect::TweakStore::bypass_for ( std::string_view anchor_id) const

Current bypass state for an anchor.

Returns std::nullopt if the anchor has no bypass entry; otherwise the live BypassValue.

◆ bypassed_anchors()

std::vector< std::string > pulp::inspect::TweakStore::bypassed_anchors ( ) const

Return every anchor id that currently has a bypass entry, regardless of whether it also has tweak records.

Used by Inspector.listTweaks to surface bypass-only anchors. A setBypass call on an anchor with no active tweaks, or one whose tweaks were later cleared, must still show up in the protocol response's bypassed map so clients and disk persistence can round-trip the bypass state.

◆ clear()

void pulp::inspect::TweakStore::clear ( )

Clear the entire table (tweaks + bypass overlay + lock set).

◆ clear_bypass()

void pulp::inspect::TweakStore::clear_bypass ( std::string_view anchor_id)

Convenience: clear the bypass for an anchor (equivalent to set_bypass(id, false)).

◆ clear_lock()

void pulp::inspect::TweakStore::clear_lock ( std::string_view anchor_id)

Convenience: clear the lock for an anchor (equivalent to set_locked(id, false)).

◆ count()

std::size_t pulp::inspect::TweakStore::count ( ) const

Total number of (anchor, property) entries.

◆ default_tweaks_path()

std::string pulp::inspect::TweakStore::default_tweaks_path ( )
static

Resolve the default pulp-tweaks.json location:

  1. $PULP_TWEAKS_FILE env var if set (verbatim — caller's responsibility to make sense of it).
  2. Walk up from cwd looking for package.json; if found, use <project_root>/pulp-tweaks.json.
  3. Otherwise <cwd>/pulp-tweaks.json.

◆ diff() [1/2]

DriftReport pulp::inspect::TweakStore::diff ( const DesignSnapshot & design) const

Classify every stored tweak against design.

Bypass overlay is ignored — a bypassed tweak can still be orphaned, and the user should see that.

◆ diff() [2/2]

DriftReport pulp::inspect::TweakStore::diff ( const std::vector< std::string > & live_anchors) const

Convenience: classify against a flat anchor list (anchor-only matching — no property-level drift).

Equivalent to building a DesignSnapshot with just anchors populated.

◆ drift_reason_str()

const char * pulp::inspect::TweakStore::drift_reason_str ( DriftReason reason)
static

Stringify a DriftReason for JSON / human output.

◆ drift_report_to_json()

std::string pulp::inspect::TweakStore::drift_report_to_json ( const DriftReport & report)
static

Render a DriftReport as a JSON string (used by pulp tweaks diff --json and the protocol layer).

Shape: { "clean": [...], "drifted": [...], "orphaned": [...], "summary": { "total", "clean", "drifted", "orphaned" } }

◆ find_drifted() [1/2]

std::vector< DriftedTweak > pulp::inspect::TweakStore::find_drifted ( const DesignSnapshot & design) const

Return only the orphaned + drifted tweaks for design — the subset the inspector drift drawer renders.

◆ find_drifted() [2/2]

std::vector< DriftedTweak > pulp::inspect::TweakStore::find_drifted ( const std::vector< std::string > & live_anchors) const

Convenience overload taking a flat anchor list.

◆ from_json()

DiskResult pulp::inspect::TweakStore::from_json ( std::string_view json)

Replace state from an in-memory JSON string.

Same error semantics as load_from_disk(). Public so tests can round-trip without touching the filesystem.

◆ is_bypassed()

bool pulp::inspect::TweakStore::is_bypassed ( std::string_view anchor_id,
std::string_view property_path ) const

Whether a specific (anchor_id, property_path) is currently bypassed (either whole-anchor or path-specific).

◆ is_locked()

bool pulp::inspect::TweakStore::is_locked ( std::string_view anchor_id) const

Whether anchor_id is currently locked.

◆ list_tweaks()

std::vector< Record > pulp::inspect::TweakStore::list_tweaks ( ) const

Return every record in the store's stable order.

Overwriting an existing (anchor, property) pair keeps its original position; JSON loads rebuild the order from file order plus any preserved locked anchors.

◆ load_from_disk()

DiskResult pulp::inspect::TweakStore::load_from_disk ( std::string_view path = {})

Replace the in-memory state with the contents of path.

Returns ok=false (without touching internal state) if the file is missing, malformed, or has an unsupported schema version.

If path is empty, resolves via default_tweaks_path().

◆ locked_anchors()

std::vector< std::string > pulp::inspect::TweakStore::locked_anchors ( ) const

Return every anchor id that currently carries a lock, in unspecified order.

Mirrors bypassed_anchors() — used by the management panel and the disk-persistence path so lock state round-trips even for anchors with no active tweaks.

◆ lookup()

std::optional< choc::value::Value > pulp::inspect::TweakStore::lookup ( std::string_view anchor_id,
std::string_view property_path ) const

Look up a specific (anchor_id, property_path).

Returns the value if set, std::nullopt otherwise.

◆ remove_anchor()

std::size_t pulp::inspect::TweakStore::remove_anchor ( std::string_view anchor_id)

Remove all entries for an anchor.

Returns the number of entries removed.

◆ remove_tweak()

bool pulp::inspect::TweakStore::remove_tweak ( std::string_view anchor_id,
std::string_view property_path )

Remove a single (anchor_id, property_path) entry.

Returns true if something was removed.

◆ save_to_disk()

DiskResult pulp::inspect::TweakStore::save_to_disk ( std::string_view path = {}) const

Atomically write the current in-memory state to path.

Writes to <path>.tmp first then renames; on success the .tmp file no longer exists at the canonical path.

If path is empty, resolves via default_tweaks_path().

◆ set_auto_save()

void pulp::inspect::TweakStore::set_auto_save ( bool enabled,
std::string_view path = {} )

Enable / disable post-mutation auto-save.

When enabled, every successful apply_tweak / remove_tweak / remove_anchor / clear / set_bypass / clear_bypass / set_locked / clear_lock call flushes the table to disk at path (or default_tweaks_path() if empty). Default OFF so unit tests don't write to disk by accident.

Set enabled=false to disable. The path is ignored when disabling.

◆ set_bypass()

void pulp::inspect::TweakStore::set_bypass ( std::string_view anchor_id,
BypassValue value )

Set the bypass state for an anchor.

  • true bypasses every tweak under the anchor.
  • A non-empty vector bypasses only those dotted paths.
  • An empty vector or false clears the bypass entirely.

◆ set_locked()

void pulp::inspect::TweakStore::set_locked ( std::string_view anchor_id,
bool locked )

Set the lock state for an anchor.

A locked anchor is protected from being cleared by a bulk operation or by re-import. locked=true adds the anchor to the lock set; locked=false removes it. Lock is a sibling overlay — it never affects whether a tweak is applied, only whether destructive bulk operations may remove it.

◆ to_json()

std::string pulp::inspect::TweakStore::to_json ( ) const

Serialize the current state to a JSON string in the on-disk schema.

Public so callers (e.g. the protocol layer's saveTweaks response) can preview without writing.

Member Data Documentation

◆ kSchemaVersion

int pulp::inspect::TweakStore::kSchemaVersion = 1
staticconstexpr

On-disk schema version. Bumped if/when we ever break the format.


The documentation for this class was generated from the following file: