com.phasmidsoftware.xmldoc.idml

Members list

Type members

Classlikes

case class Conflict(self: String, key: String, baseValue: Option[String], leftValue: Option[String], rightValue: Option[String]) extends MergeOutcome

A genuine conflict: both sides changed the same thing differently, and it isn't this code's job to guess which one wins.

A genuine conflict: both sides changed the same thing differently, and it isn't this code's job to guess which one wins.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait MergeOutcome
class Object
trait Matchable
class Any
Show all
case class Deleted(node: NodeRef) extends Edit

A node present in the base tree with no match in the modified tree - i.e. removed.

A node present in the base tree with no match in the modified tree - i.e. removed.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait Edit
class Object
trait Matchable
class Any
Show all

Whether a PageItem's dimension (or the margin on either side of it) stays fixed relative to its parent, or is free to vary, under InDesign's object-based layout rules ("Liquid Layout").

Whether a PageItem's dimension (or the margin on either side of it) stays fixed relative to its parent, or is free to vary, under InDesign's object-based layout rules ("Liquid Layout").

Corresponds exactly to InDesign's own DimensionsConstraints enum (ExtendScript), which has only these two values - confirmed against the InDesign scripting API reference, since this isn't otherwise documented anywhere in the IDML files themselves.

Attributes

Supertypes
trait Enum
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
sealed trait Edit

A detected edit between a base tree and one modified version of it, per MERGE.md's "edit detection" phase (Lindholm's terminology: the set of edits E is what's actually fed to the merge/reconciliation step, not the whole tree). There's no "unchanged" case - a matched node whose content didn't change simply produces no Edit at all.

A detected edit between a base tree and one modified version of it, per MERGE.md's "edit detection" phase (Lindholm's terminology: the set of edits E is what's actually fed to the merge/reconciliation step, not the whole tree). There's no "unchanged" case - a matched node whose content didn't change simply produces no Edit at all.

Attributes

Supertypes
class Object
trait Matchable
class Any
Known subtypes
class Deleted
class Inserted
class Updated
object EditDetector

Detects edits between a base tree and one modified version, by combining TreeMatcher's matching with a per-node attribute diff. Structural changes (insertions/deletions, at whatever depth they occur) fall out of TreeMatcher's own whole-tree walk for free; this only adds content-level change detection for the nodes that do still correspond.

Detects edits between a base tree and one modified version, by combining TreeMatcher's matching with a per-node attribute diff. Structural changes (insertions/deletions, at whatever depth they occur) fall out of TreeMatcher's own whole-tree walk for free; this only adds content-level change detection for the nodes that do still correspond.

Deliberately narrow: only a matched node's own attributes are compared, not its children's order (a "move" among already-matched siblings, or a reparenting) - PcsEditDetector/PcsMerger handle that instead; ThreeWayMerger combines the two.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type

A real, runnable git merge driver for .idml files (see MERGE.md's "Eventual integration: a git merge driver"): merge(base, ours, theirs) mutates ours in place - exactly git's own %O %A %B contract, ours being the file to leave in whatever state should actually be used.

A real, runnable git merge driver for .idml files (see MERGE.md's "Eventual integration: a git merge driver"): merge(base, ours, theirs) mutates ours in place - exactly git's own %O %A %B contract, ours being the file to leave in whatever state should actually be used.

Every part IdmlPackage.parts lists (Spreads, Stories, MasterSpreads, Resources, ...) goes through IdmlPackageMerger, each part a normal ThreeWayMerger.merge. designmap.xml itself is handled separately and much more narrowly: it's a far richer element than "a list of part references" (its own Self, plenty of other Self-bearing children like Language resource definitions, and - confirmed by direct inspection - a leading processing instruction that `scala.xml`'s parser silently drops and `GenericElement` has no way to put back). A full 3-way merge of all of that is out of scope here; instead, `ours`'s own `designmap.xml` is left completely untouched *unless* a part was actually added or removed, in which case its exact text is surgically patched - one line inserted or removed - rather than parsed and rebuilt, so everything else about it (including that processing instruction) survives byte for byte.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
class IdmlPackage

An open IDML package: a zip file plus its designmap.xml manifest, parsed only as far as discovering the other parts it references — everything is still fully generic at this stage (GenericElement), since no specialist types exist yet.

An open IDML package: a zip file plus its designmap.xml manifest, parsed only as far as discovering the other parts it references — everything is still fully generic at this stage (GenericElement), since no specialist types exist yet.

Value parameters

designmap

the parsed content of designmap.xml.

file

the underlying .idml file.

Attributes

Companion
object
Supertypes
class Object
trait Matchable
class Any
object IdmlPackage

Attributes

Companion
class
Supertypes
class Object
trait Matchable
class Any
Self type

Merges every part of an IDML package - one ThreeWayMerger.merge call per part still present on all three sides, plus the same present/absent case analysis Merger/PcsMerger already use for a single node, just one level up: at the granularity of "does this whole part exist", not "does this attribute/relation exist".

Merges every part of an IDML package - one ThreeWayMerger.merge call per part still present on all three sides, plus the same present/absent case analysis Merger/PcsMerger already use for a single node, just one level up: at the granularity of "does this whole part exist", not "does this attribute/relation exist".

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
case class Inserted(node: NodeRef) extends Edit

A node present in the modified tree with no match in the base - i.e. newly created.

A node present in the modified tree with no match in the base - i.e. newly created.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait Edit
class Object
trait Matchable
class Any
Show all

The value of a HorizontalLayoutConstraints or VerticalLayoutConstraints attribute on any IDML PageItem (TextFrame, Rectangle, Oval, ... - confirmed against real content: both element types in HelloWorld2.idml carry this attribute with an identical shape, matching InDesign's own PageItem.horizontalLayoutConstraints/verticalLayoutConstraints properties, which the ExtendScript API documents as applying to PageItem generally, not to any one subtype).

The value of a HorizontalLayoutConstraints or VerticalLayoutConstraints attribute on any IDML PageItem (TextFrame, Rectangle, Oval, ... - confirmed against real content: both element types in HelloWorld2.idml carry this attribute with an identical shape, matching InDesign's own PageItem.horizontalLayoutConstraints/verticalLayoutConstraints properties, which the ExtendScript API documents as applying to PageItem generally, not to any one subtype).

The three values are, in order: the constraint on the margin/space before the item (left, for horizontal; top, for vertical), on the item's own dimension (width or height), and on the margin/space after it (right or bottom).

Value parameters

after

the constraint on the space after the item (right margin / bottom margin).

before

the constraint on the space before the item (left margin / top margin).

dimension

the constraint on the item's own dimension (width / height).

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all

Attributes

Companion
class
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
sealed trait MergeOutcome

The outcome of combining left's and right's edits (each relative to a common base) for one node or one attribute.

The outcome of combining left's and right's edits (each relative to a common base) for one node or one attribute.

Attributes

Supertypes
class Object
trait Matchable
class Any
Known subtypes
case class MergedAttributeChange(self: String, key: String, baseValue: Option[String], newValue: Option[String]) extends MergeOutcome

One attribute change that's safe to apply - made by only one side, or made by both sides to the same new value.

One attribute change that's safe to apply - made by only one side, or made by both sides to the same new value.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait MergeOutcome
class Object
trait Matchable
class Any
Show all
case class MergedDelete(node: NodeRef) extends MergeOutcome

A node to be removed from the merged result - deleted by both sides in agreement. If only one side deleted it while the other updated it, that's a Conflict instead (see below) - Lindholm treats this "Delete/Edit" case as optional and lets deletion win by default, but Kaining's own catalogue of expected outcomes (see MERGE.md) calls for it to be a real conflict, which is what this implements.

A node to be removed from the merged result - deleted by both sides in agreement. If only one side deleted it while the other updated it, that's a Conflict instead (see below) - Lindholm treats this "Delete/Edit" case as optional and lets deletion win by default, but Kaining's own catalogue of expected outcomes (see MERGE.md) calls for it to be a real conflict, which is what this implements.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait MergeOutcome
class Object
trait Matchable
class Any
Show all
case class MergedInsert(node: NodeRef) extends MergeOutcome

A node inserted by (at least) one side - safe to apply.

A node inserted by (at least) one side - safe to apply.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait MergeOutcome
class Object
trait Matchable
class Any
Show all
object Merger

Combines two independent sets of edits (left and right, both relative to the same base) into one merge result, per MERGE.md's design direction. Built directly on EditDetector: nodes edited by only one side are trivially safe to apply; nodes edited by both sides are reconciled attribute-by-attribute, so (per the running HelloWorld2A/HelloWorld2B example) one side moving an object and the other restyling it combine cleanly, while two sides changing the same attribute differently is reported as a Conflict, not silently resolved either way. A node deleted by one side and updated by the other is also a Conflict (per Kaining's own catalogue of expected outcomes, 06-delete-vs-modify in MERGE.md - this deliberately disagrees with Lindholm's stated default of letting deletion win silently).

Combines two independent sets of edits (left and right, both relative to the same base) into one merge result, per MERGE.md's design direction. Built directly on EditDetector: nodes edited by only one side are trivially safe to apply; nodes edited by both sides are reconciled attribute-by-attribute, so (per the running HelloWorld2A/HelloWorld2B example) one side moving an object and the other restyling it combine cleanly, while two sides changing the same attribute differently is reported as a Conflict, not silently resolved either way. A node deleted by one side and updated by the other is also a Conflict (per Kaining's own catalogue of expected outcomes, 06-delete-vs-modify in MERGE.md - this deliberately disagrees with Lindholm's stated default of letting deletion win silently).

Deliberately narrow, matching EditDetector's own scope: only attribute-level content is reconciled, not child order/position - PcsMerger handles that; ThreeWayMerger combines the two.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Merger.type
case class PackageMergeResult(partOutcomes: Seq[PartOutcome], conflicts: Seq[PartConflict])

The result of merging every part IdmlPackage.parts lists (Spreads, Stories, MasterSpreads, Resources, ...) across base/left/right - deliberately not designmap.xml itself, which IdmlMergeDriver handles separately (see its own doc): designmap.xml is a much richer element than "a list of part references" (it has its own Self, and plenty of other Self-bearing children of its own, e.g. Language resource definitions) - a real 3-way merge of all of that is out of scope here; only the specific list of idPkg:* references needs to track what partOutcomes decided.

The result of merging every part IdmlPackage.parts lists (Spreads, Stories, MasterSpreads, Resources, ...) across base/left/right - deliberately not designmap.xml itself, which IdmlMergeDriver handles separately (see its own doc): designmap.xml is a much richer element than "a list of part references" (it has its own Self, and plenty of other Self-bearing children of its own, e.g. Language resource definitions) - a real 3-way merge of all of that is out of scope here; only the specific list of idPkg:* references needs to track what partOutcomes decided.

Value parameters

conflicts

every part-level conflict found; if non-empty, partOutcomes should not be applied (mirrors PcsMerger/ThreeWayMerger's own "conflicts present means don't trust the resolved side" contract).

partOutcomes

every part that needs to change - additions, edits, and removals.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
case class PackagePart(partType: String, src: String)

A reference to a package part declared in designmap.xml via an idPkg:* element, e.g. ``.

A reference to a package part declared in designmap.xml via an idPkg:* element, e.g. ``.

Value parameters

partType

the local part type, e.g. "Story", "Spread", "MasterSpread", "Graphic".

src

the path of the referenced entry within the zip, e.g. "Stories/Story_ue6.xml".

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
case class PartConflict(src: String, conflicts: Seq[StructuralConflict])

A whole part-level conflict - conflicts is empty only for the "one side deleted, the other genuinely edited" and "both sides added a different part at the same src" cases, where the disagreement is about the part's very existence, not any specific slot within it.

A whole part-level conflict - conflicts is empty only for the "one side deleted, the other genuinely edited" and "both sides added a different part at the same src" cases, where the disagreement is about the part's very existence, not any specific slot within it.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
case class PartContent(src: String, partType: String, content: GenericElement) extends PartOutcome

src should exist with this content in the merged package - either a genuine edit, or a part only one side added.

src should exist with this content in the merged package - either a genuine edit, or a part only one side added.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait PartOutcome
class Object
trait Matchable
class Any
Show all
sealed trait PartOutcome

One part's outcome from a whole-package 3-way merge - only ever reported for a part that needs an actual change; a part left untouched by both sides needs no entry at all (base's own copy, already sitting in left's file unmodified, is already correct).

One part's outcome from a whole-package 3-way merge - only ever reported for a part that needs an actual change; a part left untouched by both sides needs no entry at all (base's own copy, already sitting in left's file unmodified, is already correct).

Attributes

Supertypes
class Object
trait Matchable
class Any
Known subtypes
class PartContent
class PartRemoved
case class PartRemoved(src: String) extends PartOutcome

src should no longer exist in the merged package - both sides deleted it, or one side deleted it and the other never touched it.

src should no longer exist in the merged package - both sides deleted it, or one side deleted it and the other never touched it.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait PartOutcome
class Object
trait Matchable
class Any
Show all
case class Story(self: String, attributes: Seq[(String, String)], children: Seq[GenericContent])

The first specialist type in the mixed parsing system described for idml: models just the Self identity of an IDML `` element, leaving everything else (style ranges, content, preferences) generic for now.

The first specialist type in the mixed parsing system described for idml: models just the Self identity of an IDML `` element, leaving everything else (style ranges, content, preferences) generic for now.

Self is InDesign's own stable identifier for an object across saves, and is the central open question for the eventual three-way merge work: whether it survives independent edits to the same base document. Starting the specialist-type system here, rather than with something structurally richer, means the first real specialist type directly exercises the thing that actually matters.

Value parameters

attributes

the element's other attributes (Self removed, so there's only one place that holds it).

children

the element's children, still fully generic.

self

the Self identity attribute, e.g. "ue6".

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
object Story

Attributes

Companion
class
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
Story.type

The real, end-to-end 3-way merge, combining Merger's attribute-level reconciliation with PcsMerger's structural one - each catches conflicts, and resolves edits, that the other cannot:

The real, end-to-end 3-way merge, combining Merger's attribute-level reconciliation with PcsMerger's structural one - each catches conflicts, and resolves edits, that the other cannot:

  • Merger decides a matched node's own tag/attributes, attribute by attribute - so two sides changing different attributes of the same node (the running HelloWorld2A/HelloWorld2B example, MergerSpec) combine cleanly. It has no notion of position at all, so it is blind to reordering and reparenting.
  • PcsMerger decides a node's position and parent - so a plain reorder or a Kaining 10-group-ungroup reparenting conflict, both invisible to Merger, are handled correctly (PcsMergerSpec). Its own Content relation, though, only ever sees a node's whole tag+attributes as one indivisible blob - by itself, it would (wrongly) report the HelloWorld2A/HelloWorld2B case above as a conflict, since it can't tell "different attributes changed" from "the same attribute changed differently".

This reconciles the two: structure (which nodes exist, in what order, under what parent) comes entirely from PcsMerger/PcsTreeBuilder; a matched node's own tag/attributes come from Merger wherever Merger has an opinion (i.e. the node has a Self) - PcsMerger's own (coarser) content resolution only fills in the rest: Self-less nodes (Properties, the PathGeometry chain, ...), which Merger never sees at all.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
case class Updated(base: NodeRef, modified: NodeRef, changedAttributes: Seq[(String, Option[String], Option[String])]) extends Edit

A matched node (same Self in both trees) whose own attributes differ.

A matched node (same Self in both trees) whose own attributes differ.

Value parameters

base

the node as it was in the base tree.

changedAttributes

one entry per attribute key that differs, as (key, valueInBase, valueInModified) - None means the attribute was absent on that side (i.e. it was added or removed, not just changed).

modified

the node as it is in the modified tree.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
trait Edit
class Object
trait Matchable
class Any
Show all