25#include <nlohmann/json.hpp>
56 throw std::invalid_argument(
"Unknown PROP_RES: " + aStr );
82 if( aStr ==
"delete" )
86 throw std::invalid_argument(
"Unknown ITEM_RES: " + aStr );
93void indexChangeTree(
const ITEM_CHANGE& aChange,
94 std::map<KIID_PATH, const ITEM_CHANGE*>& aIndex )
96 aIndex[aChange.id] = &aChange;
98 for(
const ITEM_CHANGE& child : aChange.children )
99 indexChangeTree( child, aIndex );
107 std::map<KIID_PATH, const ITEM_CHANGE*>
index;
110 indexChangeTree( c,
index );
118 std::map<wxString, const PROPERTY_DELTA*>
index;
133 if( aOurs && !aTheirs )
139 if( !aOurs && aTheirs )
150 wxASSERT( aOurs || aTheirs );
152 if( !aOurs && !aTheirs )
174 const bool baselinesMatch = aOurs->
before == aTheirs->
before;
217 r.
name = aJson.at(
"name" ).get<wxString>();
220 if( aJson.contains(
"custom" ) )
236 j[
"id"] =
id.AsString();
239 nlohmann::json arr = nlohmann::json::array();
242 arr.push_back( p.ToJson() );
244 j[
"props"] = std::move( arr );
252 r.
id =
KIID_PATH( aJson.at(
"id" ).get<wxString>() );
255 for(
const auto& p : aJson.at(
"props" ) )
266 nlohmann::json arr = nlohmann::json::array();
269 arr.push_back( a.ToJson() );
271 j[
"actions"] = std::move( arr );
273 nlohmann::json unr = nlohmann::json::array();
276 unr.push_back( u.AsString() );
278 j[
"unresolved"] = std::move( unr );
289 for(
const auto& a : aJson.at(
"actions" ) )
292 for(
const auto& u : aJson.at(
"unresolved" ) )
309 std::set<KIID_PATH> processed;
311 auto noteSideEffects = [&](
const ITEM_CHANGE& aChange )
321 for(
const auto& [
id, ourChange] : ourIndex )
323 auto it = theirIndex.find(
id );
325 if( it == theirIndex.end() )
329 processed.insert(
id );
330 noteSideEffects( *ourChange );
331 noteSideEffects( *theirChange );
340 plan.
actions.push_back( std::move( r ) );
352 plan.
actions.push_back( std::move( r ) );
363 plan.
actions.push_back( std::move( r ) );
378 plan.
actions.push_back( std::move( r ) );
394 plan.
actions.push_back( std::move( r ) );
403 if( ourChange->properties.empty() && theirChange->
properties.empty()
404 && ourChange->children.empty() && theirChange->
children.empty() )
410 plan.
actions.push_back( std::move( r ) );
422 std::set<wxString> allNames;
424 for(
const auto& [n,
_] : ourProps ) allNames.insert( n );
425 for(
const auto& [n,
_] : theirProps ) allNames.insert( n );
427 bool hasUnresolvedProp =
false;
429 for(
const wxString&
name : allNames )
431 auto ourIt = ourProps.find(
name );
432 auto theirIt = theirProps.find(
name );
434 const PROPERTY_DELTA* ourDelta = ourIt != ourProps.end() ? ourIt->second :
nullptr;
435 const PROPERTY_DELTA* theirDelta = theirIt != theirProps.end() ? theirIt->second :
nullptr;
441 p.
kind = outcome.kind;
442 r.
props.push_back( std::move( p ) );
444 if( outcome.isUnresolved )
445 hasUnresolvedProp =
true;
448 if( hasUnresolvedProp )
451 plan.
actions.push_back( std::move( r ) );
460 plan.
actions.push_back( std::move( r ) );
464 for(
const auto& [
id, ourChange] : ourIndex )
466 if( processed.count(
id ) )
469 noteSideEffects( *ourChange );
474 switch( ourChange->kind )
490 plan.
actions.push_back( std::move( r ) );
493 for(
const auto& [
id, theirChange] : theirIndex )
495 if( processed.count(
id ) || ourIndex.count(
id ) )
498 noteSideEffects( *theirChange );
503 switch( theirChange->kind )
519 plan.
actions.push_back( std::move( r ) );
static DIFF_VALUE FromJson(const nlohmann::json &aJson)
MERGE_PLAN Plan(const DOCUMENT_DIFF &aAncestorOurs, const DOCUMENT_DIFF &aAncestorTheirs) const
Plan the merge given the canonical pair of diffs.
bool ChangeInvalidatesZone(const ITEM_CHANGE &aChange)
Whether a change to an item of the given type invalidates any overlapping filled zones.
ITEM_RES
Resolution kind for a whole item.
const char * PropResToString(PROP_RES aRes)
Canonical lower-case spellings for PROP_RES used inside the JSON serialization of PROPERTY_RESOLUTION...
PROP_RES PropResFromString(const std::string &aStr)
PROPERTY_RESOLUTION_OUTCOME ResolvePropertyConflict(const PROPERTY_DELTA *aOurs, const PROPERTY_DELTA *aTheirs, const KICAD_MERGE_ENGINE::OPTIONS &aOptions)
Decide how to resolve a single property edit between two sides.
ITEM_RES ItemResFromString(const std::string &aStr)
PROP_RES
Resolution kind for a single property of a single item.
bool ChangeRequiresConnectivityRebuild(const ITEM_CHANGE &aChange)
Whether a change to an item of the given type requires the connectivity graph to be rebuilt.
std::map< KIID_PATH, const ITEM_CHANGE * > IndexChangesByKiid(const DOCUMENT_DIFF &aDiff)
Flatten a DOCUMENT_DIFF's ITEM_CHANGE tree into a KIID_PATH -> ITEM_CHANGE* map, recursing into child...
const char * ItemResToString(ITEM_RES aRes)
Canonical snake_case spellings used in MERGE_PLAN JSON serialization (take_ours / take_theirs / take_...
std::map< wxString, const PROPERTY_DELTA * > IndexPropertiesByName(const ITEM_CHANGE &aChange)
Index property deltas inside one ITEM_CHANGE by property name.
The full set of changes between two parsed documents of one type.
std::vector< ITEM_CHANGE > changes
One change record on a single item.
std::vector< PROPERTY_DELTA > properties
std::vector< ITEM_CHANGE > children
std::vector< PROPERTY_RESOLUTION > props
static ITEM_RESOLUTION FromJson(const nlohmann::json &aJson)
bool operator==(const ITEM_RESOLUTION &aOther) const
nlohmann::json ToJson() const
bool preferAutoMerge
When true, property-orthogonal edits auto-merge silently.
bool autoResolveEqualValues
When true and a property edit conflicts but the side values are equal, the resolution is automaticall...
Result of planning a 3-way merge.
bool requiresConnectivityRebuild
std::vector< ITEM_RESOLUTION > actions
nlohmann::json ToJson() const
std::vector< KIID_PATH > unresolved
static MERGE_PLAN FromJson(const nlohmann::json &aJson)
Single (name, before, after) triple for one mutated property on an item.
Per-property merge decision result.
static PROPERTY_RESOLUTION FromJson(const nlohmann::json &aJson)
nlohmann::json ToJson() const
bool operator==(const PROPERTY_RESOLUTION &aOther) const