Source code for skim.application.parsers.vial_parser
"""Parser for Vial .vil keymap format.
This module provides the :class:`VialParser` for parsing keymap files
exported from the Vial keyboard configurator. Vial files use a nested
structure with clusters of keys rather than flat layer arrays.
The Vial format structure::
{
"version": 1,
"layout": [
[ // Layer 0
["KC_Q", "KC_W", ...], // Cluster 0
["KC_E", "KC_R", ...], // Cluster 1
...
],
[ // Layer 1
...
],
...
],
...
}
Example:
>>> parser = VialParser()
>>> layers = parser.parse(vil_content)
>>> len(layers[0]) # Keys per layer after flattening
60
"""
import json
from skim.application.layer_transformer import LayerAdaptor
[docs]
class VialParser:
"""Parses Vial keymap files (.vil) and transforms to Skim format.
Vial is a popular GUI keyboard configurator that exports keymaps
in a nested JSON structure organized by clusters. This parser
flattens the cluster structure and reorders keys to match
Skim's expected layout format.
The transformation is handled by :class:`LayerAdaptor` after
initial parsing.
Example:
>>> parser = VialParser()
>>> with open("keymap.vil") as f:
... content = f.read()
>>> layers = parser.parse(content)
>>> len(layers) # Number of layers
8
"""
[docs]
def parse(self, content: str) -> list[list[str]]:
"""Parse Vial content and extract keycode layers.
Parses the nested Vial JSON structure, flattens the cluster
organization, and transforms the key ordering to match
Skim's internal format.
Args:
content: JSON string content of the .vil keymap file.
Returns:
List of layers, where each layer is a flat list of 60
keycode strings in Skim's internal order.
Raises:
ValueError: If JSON is invalid, missing 'layout' key,
or structure is incorrect.
Example:
>>> content = Path("my-keymap.vil").read_text()
>>> layers = parser.parse(content)
>>> layers[0][:6] # First 6 keys of first layer
['KC_Q', 'KC_W', 'KC_E', 'KC_R', 'KC_T', 'KC_Y']
"""
try:
data = json.loads(content)
except json.JSONDecodeError as e:
raise ValueError(f"Invalid JSON: {e}") from e
if "layout" not in data:
raise ValueError("Missing 'layout' key in vial data")
layout = data["layout"]
if not isinstance(layout, list):
raise ValueError("'layout' must be a list")
return LayerAdaptor.from_vial(layout)