Skip to content

Implement inheritance of config trees (without YAML anchors...) #1063

@whisperity

Description

@whisperity

Because YAML anchors do not allow specialising a child node of an anchored-in tree, we need to instead roll our own joint of merging user-specific changes via inheritance.

Use case

  • I have three profiles (one is default which is what contour supplies, then I have master and light which are two themed customised things). When Contour comes with changes to the default schema, it's a PITA to upgrade the other two profiles because a simple diff tool just can't help as my custom profiles are always additions versus the default.
  • Automatic update of config files will get messy if entire sub-trees need update which may or may not have some keys.

Proposal

1. Hardcode for each top-level listing map (e.g. profiles and colour_schemes) the __default__ key. This is the key where Contour's "official" configuration should be put (e.g., in the contour generate config ... output).

This will make updates to the official configuration easier, as we need to only update one well-defined and reserved tree.

2. (Optionally) Introduce the __inherits__ or __base__ (I'm purposefully using some reserved underscore mangling yadda here) which takes as an argument a single (or multiple?) other named entity from the same tree: e.g., a profile might inherit another profile.

This could make custom configurations more composable (a'la CMakePresets), but might make the implementation unnecessarily messy!

3. (Irrespective of whether 2. is implemented...) when resolving a specific <top-level-tree-structure>.<user-defined-identifier>.whatever.blah key, use the following logic (in this example, rolling with the profiles, but the colour_schemes is the same yadda!):

  1. If profiles.foo.whatever.blah exist, resolve to that value.
  2. If profiles.foo.whatever.blah does not exist, but profiles.<T>.whatever.blah exists, resolve to that.
    • If entities might inherit from a single but user-specified base "class": <T> is that
    • If entities might inherit from a list of multiple user-specified base classes: <T> is the last in that list
    • If entities might not user-customisable inherit, <T> is __default__
  3. If no such value exists, fall back to Contour's baked-in default and emit a warning

4. When new keys are added to the schema (a.k.a. when the warning mentioned above is emitted), optionally offer merging such changes into the __default__ base "class". This way, it will also automatically be inherited into every user-customised profile.

Example

With this, I could achieve the following way of customisation which would make my profile YAML easier to read and edit:

profiles:
  __default__:
     # All the hardcoded b.s.
     ...

  master:
    # __base__: "__default__" (implicitly?)
    font:
      size: 14
      regular:
        family: "JetBrainsMono"

    permissions:
       capture_buffer: allow

    colors: "dracula"

colour_schemes:
    __default__:
       # Similarly, the default stuff...
       ...

   dracula:
     # __base__: "__default__"
     default:
       background: "#282a36"
       foreground: "#f8f8f2"

Why not YAML anchors instead?

default:
  font:
     regular: "JetBrains Mono"
     size: 12

my_profile: &<< default # I have no fucking idea about the syntax
  font:
     size: 14
     # Expectation: "regular" stays the same

YAML anchors do not support the use case described in this ticket, and the Expectation: line above does NOT hold...

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestfeature-requestUser requested featuresfrontendContour Terminal Emulator (GUI frontend)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions