Compare commits
8 commits
develop
...
python_opt
Author | SHA1 | Date | |
---|---|---|---|
|
e293bf243d | ||
|
286acfe7fd | ||
|
6d20b28354 | ||
|
846da06380 | ||
|
243fc17e41 | ||
|
f394f23ac6 | ||
|
0ca53fa307 | ||
|
8c361d6c41 |
22 changed files with 661 additions and 507 deletions
|
@ -1,34 +1,22 @@
|
||||||
{
|
{
|
||||||
|
"$id": "qmk.api.keyboard.v1",
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{ "$ref": "qmk.keyboard.v1" },
|
{"$ref": "qmk.keyboard.v1"},
|
||||||
{
|
{
|
||||||
"$id": "qmk.api.keyboard.v1",
|
"properties": {
|
||||||
"keymaps": {
|
"keymaps": {
|
||||||
"type": "string"
|
"type": "object",
|
||||||
},
|
"properties": {
|
||||||
"parse_errors": {
|
"url": {"type": "string"}
|
||||||
"type": "array",
|
}
|
||||||
"items": {
|
|
||||||
"type": "string"
|
},
|
||||||
}
|
"parse_errors": {"$ref": "qmk.definitions.v1#/string_array"},
|
||||||
},
|
"parse_warnings": {"$ref": "qmk.definitions.v1#/string_array"},
|
||||||
"parse_warnings": {
|
"processor_type": {"type": "string"},
|
||||||
"type": "array",
|
"protocol": {"type": "string"},
|
||||||
"items": {
|
"keyboard_folder": {"type": "string"},
|
||||||
"type": "string"
|
"platform": {"type": "string"}
|
||||||
}
|
|
||||||
},
|
|
||||||
"processor_type": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"protocol": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"keyboard_folder": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"platform": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
107
data/schemas/definitions.jsonschema
Normal file
107
data/schemas/definitions.jsonschema
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"$id": "qmk.definitions.v1",
|
||||||
|
"title": "Common definitions used across QMK's jsonschemas.",
|
||||||
|
"type": "object",
|
||||||
|
"boolean_array": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {"type": "boolean"}
|
||||||
|
},
|
||||||
|
"filename": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1,
|
||||||
|
"pattern": "^[0-9a-z_]*$"
|
||||||
|
},
|
||||||
|
"hex_number_2d": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^0x[0-9A-F]{2}$"
|
||||||
|
},
|
||||||
|
"hex_number_4d": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^0x[0-9A-F]{4}$"
|
||||||
|
},
|
||||||
|
"text_identifier": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1,
|
||||||
|
"maxLength": 250
|
||||||
|
},
|
||||||
|
"layout_macro": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["LAYOUT", "LAYOUT_planck_1x2uC"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^LAYOUT_[0-9a-z_]*$"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"key_unit": {
|
||||||
|
"type": "number",
|
||||||
|
"min": 0.25
|
||||||
|
},
|
||||||
|
"mcu_pin_array": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/mcu_pin"}
|
||||||
|
},
|
||||||
|
"mcu_pin": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[A-K]\\d{1,2}$"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^LINE_PIN\\d{1,2}$"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"multipleOf": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"signed_decimal": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"signed_int": {
|
||||||
|
"type": "number",
|
||||||
|
"multipleOf": 1
|
||||||
|
}
|
||||||
|
"signed_int_8": {
|
||||||
|
"type": "number",
|
||||||
|
"min": -127,
|
||||||
|
"max": 127,
|
||||||
|
"multipleOf": 1
|
||||||
|
}
|
||||||
|
"string_array": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"string_object": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unsigned_decimal": {
|
||||||
|
"type": "number",
|
||||||
|
"min": 0
|
||||||
|
},
|
||||||
|
"unsigned_int": {
|
||||||
|
"type": "number",
|
||||||
|
"min": 0,
|
||||||
|
"multipleOf": 1
|
||||||
|
}
|
||||||
|
"unsigned_int_8": {
|
||||||
|
"type": "number",
|
||||||
|
"min": 0,
|
||||||
|
"max": 255,
|
||||||
|
"multipleOf": 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,24 +1,12 @@
|
||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"$id": "qmk.keyboard.v1",
|
"$id": "qmk.keyboard.v1",
|
||||||
"title": "Keyboard Information",
|
"title": "Keyboard Information",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"keyboard_name": {
|
"keyboard_name": {"$ref": "qmk.definitions.v1#/text_identifier"},
|
||||||
"type": "string",
|
"maintainer": {"$ref": "qmk.definitions.v1#/text_identifier"},
|
||||||
"minLength": 2,
|
"manufacturer": {"$ref": "qmk.definitions.v1#/text_identifier"},
|
||||||
"maxLength": 250
|
|
||||||
},
|
|
||||||
"maintainer": {
|
|
||||||
"type": "string",
|
|
||||||
"minLength": 2,
|
|
||||||
"maxLength": 250
|
|
||||||
},
|
|
||||||
"manufacturer": {
|
|
||||||
"type": "string",
|
|
||||||
"minLength": 2,
|
|
||||||
"maxLength": 250
|
|
||||||
},
|
|
||||||
"url": {
|
"url": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uri"
|
"format": "uri"
|
||||||
|
@ -40,62 +28,25 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["COL2ROW", "ROW2COL"]
|
"enum": ["COL2ROW", "ROW2COL"]
|
||||||
},
|
},
|
||||||
"debounce": {
|
"debounce": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||||
"type": "number",
|
"height": {"$ref": "qmk.definitions.v1#/key_unit"},
|
||||||
"min": 0,
|
"width": {"$ref": "qmk.definitions.v1#/key_unit"},
|
||||||
"multipleOf": 1
|
|
||||||
},
|
|
||||||
"height": {
|
|
||||||
"type": "number",
|
|
||||||
"min": 0.25
|
|
||||||
},
|
|
||||||
"width": {
|
|
||||||
"type": "number",
|
|
||||||
"min": 0.25
|
|
||||||
},
|
|
||||||
"community_layouts": {
|
"community_layouts": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {"$ref": "qmk.definitions.v1#/filename"}
|
||||||
"type": "string",
|
|
||||||
"minLength": 2,
|
|
||||||
"pattern": "^[0-9a-z_]*$"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"features": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {"type": "boolean"}
|
|
||||||
},
|
},
|
||||||
|
"features": {"$ref": "qmk.definitions.v1#/boolean_array"},
|
||||||
"indicators": {
|
"indicators": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"caps_lock": {
|
"caps_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||||
"type": "string",
|
"num_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||||
"pattern": "^[A-K]\\d{1,2}$"
|
"scroll_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"}
|
||||||
},
|
|
||||||
"num_lock": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[A-K]\\d{1,2}$"
|
|
||||||
},
|
|
||||||
"scroll_lock": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[A-K]\\d{1,2}$"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"layout_aliases": {
|
"layout_aliases": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {
|
"additionalProperties": {"$ref": "qmk.definitions.v1#/layout_macro"}
|
||||||
"oneOf": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["LAYOUT", "LAYOUT_planck_1x2uC"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^LAYOUT_[0-9a-z_]*$"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"layouts": {
|
"layouts": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -109,11 +60,7 @@
|
||||||
"c_macro": {
|
"c_macro": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"key_count": {
|
"key_count": {"$ref": "qmk.definitions.v1#/key_unit"},
|
||||||
"type": "number",
|
|
||||||
"min": 0,
|
|
||||||
"multipleOf": 1
|
|
||||||
},
|
|
||||||
"layout": {
|
"layout": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
@ -131,34 +78,14 @@
|
||||||
"multipleOf": 1
|
"multipleOf": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"h": {
|
"key_count": {"$ref": "qmk.definitions.v1#/key_unit"},
|
||||||
"type": "number",
|
"r": {"$ref": "qmk.definitions.v1#/unsigned_decimal"},
|
||||||
"min": 0.25
|
"rx": {"$ref": "qmk.definitions.v1#/unsigned_decimal"},
|
||||||
},
|
"ry": {"$ref": "qmk.definitions.v1#/unsigned_decimal"},
|
||||||
"r": {
|
"h": {"$ref": "qmk.definitions.v1#/key_unit"},
|
||||||
"type": "number",
|
"w": {"$ref": "qmk.definitions.v1#/key_unit"},
|
||||||
"min": 0
|
"x": {"$ref": "qmk.definitions.v1#/key_unit"},
|
||||||
},
|
"y": {"$ref": "qmk.definitions.v1#/key_unit"}
|
||||||
"rx": {
|
|
||||||
"type": "number",
|
|
||||||
"min": 0
|
|
||||||
},
|
|
||||||
"ry": {
|
|
||||||
"type": "number",
|
|
||||||
"min": 0
|
|
||||||
},
|
|
||||||
"w": {
|
|
||||||
"type": "number",
|
|
||||||
"min": 0.25
|
|
||||||
},
|
|
||||||
"x": {
|
|
||||||
"type": "number",
|
|
||||||
"min": 0
|
|
||||||
},
|
|
||||||
"y": {
|
|
||||||
"type": "number",
|
|
||||||
"min": 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,73 +98,10 @@
|
||||||
"properties": {
|
"properties": {
|
||||||
"direct": {
|
"direct": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {$ref": "qmk.definitions.v1#/mcu_pin_array"}
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"oneOf": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[A-K]\\d{1,2}$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^LINE_PIN\\d{1,2}$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "number",
|
|
||||||
"multipleOf": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"cols": {
|
"cols": {"$ref": "qmk.definitions.v1#/mcu_pin_array"},
|
||||||
"type": "array",
|
"rows": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}
|
||||||
"items": {
|
|
||||||
"oneOf": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[A-K]\\d{1,2}$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^LINE_PIN\\d{1,2}$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "number",
|
|
||||||
"multipleOf": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rows": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"oneOf": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[A-K]\\d{1,2}$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^LINE_PIN\\d{1,2}$"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "number",
|
|
||||||
"multipleOf": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rgblight": {
|
"rgblight": {
|
||||||
|
@ -250,47 +114,19 @@
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"brightness_steps": {
|
"brightness_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||||
"type": "number",
|
"hue_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||||
"min": 0,
|
"led_count": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||||
"multipleOf": 1
|
"max_brightness": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||||
},
|
"pin": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||||
"hue_steps": {
|
"saturation_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||||
"type": "number",
|
|
||||||
"min": 0,
|
|
||||||
"multipleOf": 1
|
|
||||||
},
|
|
||||||
"led_count": {
|
|
||||||
"type": "number",
|
|
||||||
"min": 0,
|
|
||||||
"multipleOf": 1
|
|
||||||
},
|
|
||||||
"max_brightness": {
|
|
||||||
"type": "number",
|
|
||||||
"min": 0,
|
|
||||||
"max": 255,
|
|
||||||
"multipleOf": 1
|
|
||||||
},
|
|
||||||
"pin": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^([A-K]\\d{1,2}|LINE_PIN\\d{1,2})$"
|
|
||||||
},
|
|
||||||
"saturation_steps": {
|
|
||||||
"type": "number",
|
|
||||||
"min": 0,
|
|
||||||
"multipleOf": 1
|
|
||||||
},
|
|
||||||
"sleep": {"type": "boolean"},
|
"sleep": {"type": "boolean"},
|
||||||
"split": {"type": "boolean"},
|
"split": {"type": "boolean"},
|
||||||
"split_count": {
|
"split_count": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"minLength": 2,
|
"minLength": 2,
|
||||||
"maxLength": 2,
|
"maxLength": 2,
|
||||||
"items": {
|
"items": {"$ref": "qmk.definitions.v1#/unsigned_int"}
|
||||||
"type": "number",
|
|
||||||
"min": 0,
|
|
||||||
"multipleOf": 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -298,40 +134,19 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"device_ver": {
|
"device_ver": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
|
||||||
"type": "string",
|
"pid": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
|
||||||
"pattern": "^[0-9A-F]x[0-9A-F][0-9A-F][0-9A-F][0-9A-F]"
|
"vid": {"$ref": "qmk.definitions.v1#/hex_number_4d"}
|
||||||
},
|
|
||||||
"pid": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[0-9A-F]x[0-9A-F][0-9A-F][0-9A-F][0-9A-F]"
|
|
||||||
},
|
|
||||||
"vid": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[0-9A-F]x[0-9A-F][0-9A-F][0-9A-F][0-9A-F]"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"qmk_lufa_bootloader": {
|
"qmk_lufa_bootloader": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"esc_output": {
|
"esc_output": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||||
"type": "string",
|
"esc_input": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||||
"pattern": "^[A-K]\\d{1,2}$"
|
"led": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||||
},
|
"speaker": {"$ref": "qmk.definitions.v1#/mcu_pin"}
|
||||||
"esc_input": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[A-K]\\d{1,2}$"
|
|
||||||
},
|
|
||||||
"led": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[A-K]\\d{1,2}$"
|
|
||||||
},
|
|
||||||
"speaker": {
|
|
||||||
"type": "string",
|
|
||||||
"pattern": "^[A-K]\\d{1,2}$"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,143 @@
|
||||||
{
|
{
|
||||||
"keyboard_name": "nop60",
|
"keyboard_name": "nop60",
|
||||||
"url": "",
|
|
||||||
"maintainer": "nasp",
|
"maintainer": "nasp",
|
||||||
"width": 15,
|
|
||||||
"height": 5,
|
"height": 5,
|
||||||
|
"width": 15,
|
||||||
|
"url": "",
|
||||||
"layouts": {
|
"layouts": {
|
||||||
"LAYOUT": {
|
"LAYOUT": {
|
||||||
"2x3u": [{"label":"Esc", "x":0, "y":0}, {"label":"!", "x":1, "y":0}, {"label":"@", "x":2, "y":0}, {"label":"#", "x":3, "y":0}, {"label":"$", "x":4, "y":0}, {"label":"%", "x":5, "y":0}, {"label":"^", "x":6, "y":0}, {"label":"&", "x":7, "y":0}, {"label":"*", "x":8, "y":0}, {"label":"(", "x":9, "y":0}, {"label":")", "x":10, "y":0}, {"label":"_", "x":11, "y":0}, {"label":"+", "x":12, "y":0}, {"label":"~", "x":13, "y":0}, {"label":"Bksp", "x":14, "y":0}, {"label":"Tab", "x":0, "y":1, "w":1.5}, {"label":"Q", "x":1.5, "y":1}, {"label":"W", "x":2.5, "y":1}, {"label":"E", "x":3.5, "y":1}, {"label":"R", "x":4.5, "y":1}, {"label":"T", "x":5.5, "y":1}, {"label":"Y", "x":6.5, "y":1}, {"label":"U", "x":7.5, "y":1}, {"label":"I", "x":8.5, "y":1}, {"label":"O", "x":9.5, "y":1}, {"label":"P", "x":10.5, "y":1}, {"label":"{", "x":11.5, "y":1}, {"label":"}", "x":12.5, "y":1}, {"label":"|", "x":13.5, "y":1, "w":1.5}, {"label":"Caps Lock", "x":0, "y":2, "w":1.75}, {"label":"A", "x":1.75, "y":2}, {"label":"S", "x":2.75, "y":2}, {"label":"D", "x":3.75, "y":2}, {"label":"F", "x":4.75, "y":2}, {"label":"G", "x":5.75, "y":2}, {"label":"H", "x":6.75, "y":2}, {"label":"J", "x":7.75, "y":2}, {"label":"K", "x":8.75, "y":2}, {"label":"L", "x":9.75, "y":2}, {"label":":", "x":10.75, "y":2}, {"label":"\"", "x":11.75, "y":2}, {"label":"Enter", "x":12.75, "y":2, "w":2.25}, {"label":"Shift", "x":0, "y":3, "w":2.25}, {"label":"Z", "x":2.25, "y":3}, {"label":"X", "x":3.25, "y":3}, {"label":"C", "x":4.25, "y":3}, {"label":"V", "x":5.25, "y":3}, {"label":"B", "x":6.25, "y":3}, {"label":"N", "x":7.25, "y":3}, {"label":"M", "x":8.25, "y":3}, {"label":"<", "x":9.25, "y":3}, {"label":">", "x":10.25, "y":3}, {"label":"?", "x":11.25, "y":3}, {"label":"Shift", "x":12.25, "y":3, "w":1.75}, {"label":"Fn", "x":14, "y":3}, {"label":"Ctrl", "x":0, "y":4, "w":1.5}, {"label":"Win", "x":1.5, "y":4}, {"label":"Alt", "x":2.5, "y":4, "w":1.5}, {"x":4, "y":4, "w":3}, {"x":7, "y":4}, {"x":8, "y":4, "w":3}, {"label":"Alt", "x":11, "y":4, "w":1.5}, {"label":"Win", "x":12.5, "y":4}, {"label":"Ctrl", "x":13.5, "y":4, "w":1.5}]
|
"layout": [
|
||||||
|
{ "label": "Esc", "x": 0, "y": 0 },
|
||||||
|
{ "label": "!", "x": 1, "y": 0 },
|
||||||
|
{ "label": "@", "x": 2, "y": 0 },
|
||||||
|
{ "label": "#", "x": 3, "y": 0 },
|
||||||
|
{ "label": "$", "x": 4, "y": 0 },
|
||||||
|
{ "label": "%", "x": 5, "y": 0 },
|
||||||
|
{ "label": "^", "x": 6, "y": 0 },
|
||||||
|
{ "label": "&", "x": 7, "y": 0 },
|
||||||
|
{ "label": "*", "x": 8, "y": 0 },
|
||||||
|
{ "label": "(", "x": 9, "y": 0 },
|
||||||
|
{ "label": ")", "x": 10, "y": 0 },
|
||||||
|
{ "label": "_", "x": 11, "y": 0 },
|
||||||
|
{ "label": "+", "x": 12, "y": 0 },
|
||||||
|
{ "label": "~", "x": 13, "y": 0 },
|
||||||
|
{ "label": "Bksp", "x": 14, "y": 0 },
|
||||||
|
{ "label": "Tab", "w": 1.5, "x": 0, "y": 1 },
|
||||||
|
{ "label": "Q", "x": 1.5, "y": 1 },
|
||||||
|
{ "label": "W", "x": 2.5, "y": 1 },
|
||||||
|
{ "label": "E", "x": 3.5, "y": 1 },
|
||||||
|
{ "label": "R", "x": 4.5, "y": 1 },
|
||||||
|
{ "label": "T", "x": 5.5, "y": 1 },
|
||||||
|
{ "label": "Y", "x": 6.5, "y": 1 },
|
||||||
|
{ "label": "U", "x": 7.5, "y": 1 },
|
||||||
|
{ "label": "I", "x": 8.5, "y": 1 },
|
||||||
|
{ "label": "O", "x": 9.5, "y": 1 },
|
||||||
|
{ "label": "P", "x": 10.5, "y": 1 },
|
||||||
|
{ "label": "{", "x": 11.5, "y": 1 },
|
||||||
|
{ "label": "}", "x": 12.5, "y": 1 },
|
||||||
|
{ "label": "|", "w": 1.5, "x": 13.5, "y": 1 },
|
||||||
|
{ "label": "Caps Lock", "w": 1.75, "x": 0, "y": 2 },
|
||||||
|
{ "label": "A", "x": 1.75, "y": 2 },
|
||||||
|
{ "label": "S", "x": 2.75, "y": 2 },
|
||||||
|
{ "label": "D", "x": 3.75, "y": 2 },
|
||||||
|
{ "label": "F", "x": 4.75, "y": 2 },
|
||||||
|
{ "label": "G", "x": 5.75, "y": 2 },
|
||||||
|
{ "label": "H", "x": 6.75, "y": 2 },
|
||||||
|
{ "label": "J", "x": 7.75, "y": 2 },
|
||||||
|
{ "label": "K", "x": 8.75, "y": 2 },
|
||||||
|
{ "label": "L", "x": 9.75, "y": 2 },
|
||||||
|
{ "label": ":", "x": 10.75, "y": 2 },
|
||||||
|
{ "label": "\"", "x": 11.75, "y": 2 },
|
||||||
|
{ "label": "Enter", "w": 2.25, "x": 12.75, "y": 2 },
|
||||||
|
{ "label": "Shift", "w": 2.25, "x": 0, "y": 3 },
|
||||||
|
{ "label": "Z", "x": 2.25, "y": 3 },
|
||||||
|
{ "label": "X", "x": 3.25, "y": 3 },
|
||||||
|
{ "label": "C", "x": 4.25, "y": 3 },
|
||||||
|
{ "label": "V", "x": 5.25, "y": 3 },
|
||||||
|
{ "label": "B", "x": 6.25, "y": 3 },
|
||||||
|
{ "label": "N", "x": 7.25, "y": 3 },
|
||||||
|
{ "label": "M", "x": 8.25, "y": 3 },
|
||||||
|
{ "label": "<", "x": 9.25, "y": 3 },
|
||||||
|
{ "label": ">", "x": 10.25, "y": 3 },
|
||||||
|
{ "label": "?", "x": 11.25, "y": 3 },
|
||||||
|
{ "label": "Shift", "w": 1.75, "x": 12.25, "y": 3 },
|
||||||
|
{ "label": "Fn", "x": 14, "y": 3 },
|
||||||
|
{ "label": "Ctrl", "w": 1.5, "x": 0, "y": 4 },
|
||||||
|
{ "label": "Win", "x": 1.5, "y": 4 },
|
||||||
|
{ "label": "Alt", "w": 1.5, "x": 2.5, "y": 4 },
|
||||||
|
{ "w": 7, "x": 4, "y": 4 },
|
||||||
|
{ "label": "Alt", "w": 1.5, "x": 11, "y": 4 },
|
||||||
|
{ "label": "Win", "x": 12.5, "y": 4 },
|
||||||
|
{ "label": "Ctrl", "w": 1.5, "x": 13.5, "y": 4 }
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"LAYOUT": {
|
"LAYOUT_2x3u": {
|
||||||
"7u": [{"label":"Esc", "x":0, "y":0}, {"label":"!", "x":1, "y":0}, {"label":"@", "x":2, "y":0}, {"label":"#", "x":3, "y":0}, {"label":"$", "x":4, "y":0}, {"label":"%", "x":5, "y":0}, {"label":"^", "x":6, "y":0}, {"label":"&", "x":7, "y":0}, {"label":"*", "x":8, "y":0}, {"label":"(", "x":9, "y":0}, {"label":")", "x":10, "y":0}, {"label":"_", "x":11, "y":0}, {"label":"+", "x":12, "y":0}, {"label":"~", "x":13, "y":0}, {"label":"Bksp", "x":14, "y":0}, {"label":"Tab", "x":0, "y":1, "w":1.5}, {"label":"Q", "x":1.5, "y":1}, {"label":"W", "x":2.5, "y":1}, {"label":"E", "x":3.5, "y":1}, {"label":"R", "x":4.5, "y":1}, {"label":"T", "x":5.5, "y":1}, {"label":"Y", "x":6.5, "y":1}, {"label":"U", "x":7.5, "y":1}, {"label":"I", "x":8.5, "y":1}, {"label":"O", "x":9.5, "y":1}, {"label":"P", "x":10.5, "y":1}, {"label":"{", "x":11.5, "y":1}, {"label":"}", "x":12.5, "y":1}, {"label":"|", "x":13.5, "y":1, "w":1.5}, {"label":"Caps Lock", "x":0, "y":2, "w":1.75}, {"label":"A", "x":1.75, "y":2}, {"label":"S", "x":2.75, "y":2}, {"label":"D", "x":3.75, "y":2}, {"label":"F", "x":4.75, "y":2}, {"label":"G", "x":5.75, "y":2}, {"label":"H", "x":6.75, "y":2}, {"label":"J", "x":7.75, "y":2}, {"label":"K", "x":8.75, "y":2}, {"label":"L", "x":9.75, "y":2}, {"label":":", "x":10.75, "y":2}, {"label":"\"", "x":11.75, "y":2}, {"label":"Enter", "x":12.75, "y":2, "w":2.25}, {"label":"Shift", "x":0, "y":3, "w":2.25}, {"label":"Z", "x":2.25, "y":3}, {"label":"X", "x":3.25, "y":3}, {"label":"C", "x":4.25, "y":3}, {"label":"V", "x":5.25, "y":3}, {"label":"B", "x":6.25, "y":3}, {"label":"N", "x":7.25, "y":3}, {"label":"M", "x":8.25, "y":3}, {"label":"<", "x":9.25, "y":3}, {"label":">", "x":10.25, "y":3}, {"label":"?", "x":11.25, "y":3}, {"label":"Shift", "x":12.25, "y":3, "w":1.75}, {"label":"Fn", "x":14, "y":3}, {"label":"Ctrl", "x":0, "y":4, "w":1.5}, {"label":"Win", "x":1.5, "y":4}, {"label":"Alt", "x":2.5, "y":4, "w":1.5}, {"x":4, "y":4, "w":7}, {"label":"Alt", "x":11, "y":4, "w":1.5}, {"label":"Win", "x":12.5, "y":4}, {"label":"Ctrl", "x":13.5, "y":4, "w":1.5}]
|
"layout": [
|
||||||
|
{ "label": "Esc", "x": 0, "y": 0 },
|
||||||
|
{ "label": "!", "x": 1, "y": 0 },
|
||||||
|
{ "label": "@", "x": 2, "y": 0 },
|
||||||
|
{ "label": "#", "x": 3, "y": 0 },
|
||||||
|
{ "label": "$", "x": 4, "y": 0 },
|
||||||
|
{ "label": "%", "x": 5, "y": 0 },
|
||||||
|
{ "label": "^", "x": 6, "y": 0 },
|
||||||
|
{ "label": "&", "x": 7, "y": 0 },
|
||||||
|
{ "label": "*", "x": 8, "y": 0 },
|
||||||
|
{ "label": "(", "x": 9, "y": 0 },
|
||||||
|
{ "label": ")", "x": 10, "y": 0 },
|
||||||
|
{ "label": "_", "x": 11, "y": 0 },
|
||||||
|
{ "label": "+", "x": 12, "y": 0 },
|
||||||
|
{ "label": "~", "x": 13, "y": 0 },
|
||||||
|
{ "label": "Bksp", "x": 14, "y": 0 },
|
||||||
|
{ "label": "Tab", "w": 1.5, "x": 0, "y": 1 },
|
||||||
|
{ "label": "Q", "x": 1.5, "y": 1 },
|
||||||
|
{ "label": "W", "x": 2.5, "y": 1 },
|
||||||
|
{ "label": "E", "x": 3.5, "y": 1 },
|
||||||
|
{ "label": "R", "x": 4.5, "y": 1 },
|
||||||
|
{ "label": "T", "x": 5.5, "y": 1 },
|
||||||
|
{ "label": "Y", "x": 6.5, "y": 1 },
|
||||||
|
{ "label": "U", "x": 7.5, "y": 1 },
|
||||||
|
{ "label": "I", "x": 8.5, "y": 1 },
|
||||||
|
{ "label": "O", "x": 9.5, "y": 1 },
|
||||||
|
{ "label": "P", "x": 10.5, "y": 1 },
|
||||||
|
{ "label": "{", "x": 11.5, "y": 1 },
|
||||||
|
{ "label": "}", "x": 12.5, "y": 1 },
|
||||||
|
{ "label": "|", "w": 1.5, "x": 13.5, "y": 1 },
|
||||||
|
{ "label": "Caps Lock", "w": 1.75, "x": 0, "y": 2 },
|
||||||
|
{ "label": "A", "x": 1.75, "y": 2 },
|
||||||
|
{ "label": "S", "x": 2.75, "y": 2 },
|
||||||
|
{ "label": "D", "x": 3.75, "y": 2 },
|
||||||
|
{ "label": "F", "x": 4.75, "y": 2 },
|
||||||
|
{ "label": "G", "x": 5.75, "y": 2 },
|
||||||
|
{ "label": "H", "x": 6.75, "y": 2 },
|
||||||
|
{ "label": "J", "x": 7.75, "y": 2 },
|
||||||
|
{ "label": "K", "x": 8.75, "y": 2 },
|
||||||
|
{ "label": "L", "x": 9.75, "y": 2 },
|
||||||
|
{ "label": ":", "x": 10.75, "y": 2 },
|
||||||
|
{ "label": "\"", "x": 11.75, "y": 2 },
|
||||||
|
{ "label": "Enter", "w": 2.25, "x": 12.75, "y": 2 },
|
||||||
|
{ "label": "Shift", "w": 2.25, "x": 0, "y": 3 },
|
||||||
|
{ "label": "Z", "x": 2.25, "y": 3 },
|
||||||
|
{ "label": "X", "x": 3.25, "y": 3 },
|
||||||
|
{ "label": "C", "x": 4.25, "y": 3 },
|
||||||
|
{ "label": "V", "x": 5.25, "y": 3 },
|
||||||
|
{ "label": "B", "x": 6.25, "y": 3 },
|
||||||
|
{ "label": "N", "x": 7.25, "y": 3 },
|
||||||
|
{ "label": "M", "x": 8.25, "y": 3 },
|
||||||
|
{ "label": "<", "x": 9.25, "y": 3 },
|
||||||
|
{ "label": ">", "x": 10.25, "y": 3 },
|
||||||
|
{ "label": "?", "x": 11.25, "y": 3 },
|
||||||
|
{ "label": "Shift", "w": 1.75, "x": 12.25, "y": 3 },
|
||||||
|
{ "label": "Fn", "x": 14, "y": 3 },
|
||||||
|
{ "label": "Ctrl", "w": 1.5, "x": 0, "y": 4 },
|
||||||
|
{ "label": "Win", "x": 1.5, "y": 4 },
|
||||||
|
{ "label": "Alt", "w": 1.5, "x": 2.5, "y": 4 },
|
||||||
|
{ "w": 3, "x": 4, "y": 4 },
|
||||||
|
{ "x": 7, "y": 4 },
|
||||||
|
{ "w": 3, "x": 8, "y": 4 },
|
||||||
|
{ "label": "Alt", "w": 1.5, "x": 11, "y": 4 },
|
||||||
|
{ "label": "Win", "x": 12.5, "y": 4 },
|
||||||
|
{ "label": "Ctrl", "w": 1.5, "x": 13.5, "y": 4 }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
{
|
{
|
||||||
"keyboard_name": "Chevron",
|
"keyboard_name": "Chevron",
|
||||||
"url": "",
|
|
||||||
"maintainer": "",
|
|
||||||
"width": 14.5,
|
"width": 14.5,
|
||||||
"height": 5,
|
"height": 5,
|
||||||
"layouts": {
|
"layouts": {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"layouts": {
|
"layouts": {
|
||||||
"LAYOUT_ortho_5x15": {
|
"LAYOUT_ortho_5x15": {
|
||||||
"layout": [
|
"layout": [
|
||||||
{"label": "Esc", "X": 0, "y": 0},
|
{"label": "Esc", "x": 0, "y": 0},
|
||||||
{"label": "1", "x": 1, "y": 0},
|
{"label": "1", "x": 1, "y": 0},
|
||||||
{"label": "2", "x": 2, "y": 0},
|
{"label": "2", "x": 2, "y": 0},
|
||||||
{"label": "3", "x": 3, "y": 0},
|
{"label": "3", "x": 3, "y": 0},
|
||||||
|
@ -22,21 +22,21 @@
|
||||||
{"label": "NumLock", "x": 12, "y": 0},
|
{"label": "NumLock", "x": 12, "y": 0},
|
||||||
{"label": "/", "x": 13, "y": 0},
|
{"label": "/", "x": 13, "y": 0},
|
||||||
{"label": "*", "x": 14, "y": 0},
|
{"label": "*", "x": 14, "y": 0},
|
||||||
{"label": "Tab", "X": 0, "y": 1},
|
{"label": "Tab", "x": 0, "y": 1},
|
||||||
{"label": "Q", "X": 1, "y": 1},
|
{"label": "Q", "x": 1, "y": 1},
|
||||||
{"label": "W", "X": 2, "y": 1},
|
{"label": "W", "x": 2, "y": 1},
|
||||||
{"label": "E", "X": 3, "y": 1},
|
{"label": "E", "x": 3, "y": 1},
|
||||||
{"label": "R", "X": 4, "y": 1},
|
{"label": "R", "x": 4, "y": 1},
|
||||||
{"label": "T", "X": 5, "y": 1},
|
{"label": "T", "x": 5, "y": 1},
|
||||||
{"label": "Y", "X": 6, "y": 1},
|
{"label": "Y", "x": 6, "y": 1},
|
||||||
{"label": "U", "X": 7, "y": 1},
|
{"label": "U", "x": 7, "y": 1},
|
||||||
{"label": "I", "X": 8, "y": 1},
|
{"label": "I", "x": 8, "y": 1},
|
||||||
{"label": "O", "X": 9, "y": 1},
|
{"label": "O", "x": 9, "y": 1},
|
||||||
{"label": "P", "X": 10, "y": 1},
|
{"label": "P", "x": 10, "y": 1},
|
||||||
{"label": "|\n\\", "X": 11, "y": 1},
|
{"label": "|\n\\", "x": 11, "y": 1},
|
||||||
{"label": "7\nHome", "X": 12, "y": 1},
|
{"label": "7\nHome", "x": 12, "y": 1},
|
||||||
{"label": "8\nUp", "X": 13, "y": 1},
|
{"label": "8\nUp", "x": 13, "y": 1},
|
||||||
{"label": "9\nPgUp", "X": 14, "y": 1},
|
{"label": "9\nPgUp", "x": 14, "y": 1},
|
||||||
{"label": "Caps", "x": 0, "y": 2},
|
{"label": "Caps", "x": 0, "y": 2},
|
||||||
{"label": "A", "x": 1, "y": 2},
|
{"label": "A", "x": 1, "y": 2},
|
||||||
{"label": "S", "x": 2, "y": 2},
|
{"label": "S", "x": 2, "y": 2},
|
||||||
|
@ -67,21 +67,21 @@
|
||||||
{"label": "1\nEnd", "x": 12, "y": 3},
|
{"label": "1\nEnd", "x": 12, "y": 3},
|
||||||
{"label": "2\nDown", "x": 13, "y": 3},
|
{"label": "2\nDown", "x": 13, "y": 3},
|
||||||
{"label": "3\nPgDn", "x": 14, "y": 3},
|
{"label": "3\nPgDn", "x": 14, "y": 3},
|
||||||
{"label": "Ctrl", "X": 0, "y": 4},
|
{"label": "Ctrl", "x": 0, "y": 4},
|
||||||
{"label": "Win", "X": 1, "y": 4},
|
{"label": "Win", "x": 1, "y": 4},
|
||||||
{"label": "Alt", "X": 2, "y": 4},
|
{"label": "Alt", "x": 2, "y": 4},
|
||||||
{"label": "Fn", "X": 3, "y": 4},
|
{"label": "Fn", "x": 3, "y": 4},
|
||||||
{"label": "Lower", "X": 4, "y": 4},
|
{"label": "Lower", "x": 4, "y": 4},
|
||||||
{"label": "Space", "X": 5, "y": 4},
|
{"label": "Space", "x": 5, "y": 4},
|
||||||
{"label": "Space", "X": 6, "y": 4},
|
{"label": "Space", "x": 6, "y": 4},
|
||||||
{"label": "Raise", "X": 7, "y": 4},
|
{"label": "Raise", "x": 7, "y": 4},
|
||||||
{"label": "Alt", "X": 8, "y": 4},
|
{"label": "Alt", "x": 8, "y": 4},
|
||||||
{"label": "Win", "X": 9, "y": 4},
|
{"label": "Win", "x": 9, "y": 4},
|
||||||
{"label": "Menu", "X": 10, "y": 4},
|
{"label": "Menu", "x": 10, "y": 4},
|
||||||
{"label": "Ctrl", "X": 11, "y": 4},
|
{"label": "Ctrl", "x": 11, "y": 4},
|
||||||
{"label": "0\nIns", "X": 12, "y": 4},
|
{"label": "0\nIns", "x": 12, "y": 4},
|
||||||
{"label": ".\nDel", "X": 13, "y": 4},
|
{"label": ".\nDel", "x": 13, "y": 4},
|
||||||
{"label": "Enter", "X": 14, "y": 4}
|
{"label": "Enter", "x": 14, "y": 4}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,10 @@ subcommands = [
|
||||||
'qmk.cli.doctor',
|
'qmk.cli.doctor',
|
||||||
'qmk.cli.fileformat',
|
'qmk.cli.fileformat',
|
||||||
'qmk.cli.flash',
|
'qmk.cli.flash',
|
||||||
|
'qmk.cli.format.c',
|
||||||
'qmk.cli.format.json',
|
'qmk.cli.format.json',
|
||||||
|
'qmk.cli.format.python',
|
||||||
|
'qmk.cli.format.text',
|
||||||
'qmk.cli.generate.api',
|
'qmk.cli.generate.api',
|
||||||
'qmk.cli.generate.config_h',
|
'qmk.cli.generate.config_h',
|
||||||
'qmk.cli.generate.dfu_header',
|
'qmk.cli.generate.dfu_header',
|
||||||
|
|
139
lib/python/qmk/cli/cformat.py
Normal file → Executable file
139
lib/python/qmk/cli/cformat.py
Normal file → Executable file
|
@ -1,137 +1,28 @@
|
||||||
"""Format C code according to QMK's style.
|
"""Point people to the new command name.
|
||||||
"""
|
"""
|
||||||
from os import path
|
import sys
|
||||||
from shutil import which
|
from pathlib import Path
|
||||||
from subprocess import CalledProcessError, DEVNULL, Popen, PIPE
|
|
||||||
|
|
||||||
from argcomplete.completers import FilesCompleter
|
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
from qmk.path import normpath
|
|
||||||
from qmk.c_parse import c_source_files
|
|
||||||
|
|
||||||
c_file_suffixes = ('c', 'h', 'cpp')
|
|
||||||
core_dirs = ('drivers', 'quantum', 'tests', 'tmk_core', 'platforms')
|
|
||||||
ignored = ('tmk_core/protocol/usb_hid', 'quantum/template', 'platforms/chibios')
|
|
||||||
|
|
||||||
|
|
||||||
def find_clang_format():
|
|
||||||
"""Returns the path to clang-format.
|
|
||||||
"""
|
|
||||||
for clang_version in range(20, 6, -1):
|
|
||||||
binary = f'clang-format-{clang_version}'
|
|
||||||
|
|
||||||
if which(binary):
|
|
||||||
return binary
|
|
||||||
|
|
||||||
return 'clang-format'
|
|
||||||
|
|
||||||
|
|
||||||
def find_diffs(files):
|
|
||||||
"""Run clang-format and diff it against a file.
|
|
||||||
"""
|
|
||||||
found_diffs = False
|
|
||||||
|
|
||||||
for file in files:
|
|
||||||
cli.log.debug('Checking for changes in %s', file)
|
|
||||||
clang_format = Popen([find_clang_format(), file], stdout=PIPE, stderr=PIPE, universal_newlines=True)
|
|
||||||
diff = cli.run(['diff', '-u', f'--label=a/{file}', f'--label=b/{file}', str(file), '-'], stdin=clang_format.stdout, capture_output=True)
|
|
||||||
|
|
||||||
if diff.returncode != 0:
|
|
||||||
print(diff.stdout)
|
|
||||||
found_diffs = True
|
|
||||||
|
|
||||||
return found_diffs
|
|
||||||
|
|
||||||
|
|
||||||
def cformat_run(files):
|
|
||||||
"""Spawn clang-format subprocess with proper arguments
|
|
||||||
"""
|
|
||||||
# Determine which version of clang-format to use
|
|
||||||
clang_format = [find_clang_format(), '-i']
|
|
||||||
|
|
||||||
try:
|
|
||||||
cli.run([*clang_format, *map(str, files)], check=True, capture_output=False, stdin=DEVNULL)
|
|
||||||
cli.log.info('Successfully formatted the C code.')
|
|
||||||
return True
|
|
||||||
|
|
||||||
except CalledProcessError as e:
|
|
||||||
cli.log.error('Error formatting C code!')
|
|
||||||
cli.log.debug('%s exited with returncode %s', e.cmd, e.returncode)
|
|
||||||
cli.log.debug('STDOUT:')
|
|
||||||
cli.log.debug(e.stdout)
|
|
||||||
cli.log.debug('STDERR:')
|
|
||||||
cli.log.debug(e.stderr)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def filter_files(files, core_only=False):
|
|
||||||
"""Yield only files to be formatted and skip the rest
|
|
||||||
"""
|
|
||||||
if core_only:
|
|
||||||
# Filter non-core files
|
|
||||||
for index, file in enumerate(files):
|
|
||||||
# The following statement checks each file to see if the file path is
|
|
||||||
# - in the core directories
|
|
||||||
# - not in the ignored directories
|
|
||||||
if not any(i in str(file) for i in core_dirs) or any(i in str(file) for i in ignored):
|
|
||||||
files[index] = None
|
|
||||||
cli.log.debug("Skipping non-core file %s, as '--core-only' is used.", file)
|
|
||||||
|
|
||||||
for file in files:
|
|
||||||
if file and file.name.split('.')[-1] in c_file_suffixes:
|
|
||||||
yield file
|
|
||||||
else:
|
|
||||||
cli.log.debug('Skipping file %s', file)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Flag only, don't automatically format.")
|
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Flag only, don't automatically format.")
|
||||||
@cli.argument('-b', '--base-branch', default='origin/master', help='Branch to compare to diffs to.')
|
@cli.argument('-b', '--base-branch', default='origin/master', help='Branch to compare to diffs to.')
|
||||||
@cli.argument('-a', '--all-files', arg_only=True, action='store_true', help='Format all core files.')
|
@cli.argument('-a', '--all-files', arg_only=True, action='store_true', help='Format all core files.')
|
||||||
@cli.argument('--core-only', arg_only=True, action='store_true', help='Format core files only.')
|
@cli.argument('--core-only', arg_only=True, action='store_true', help='Format core files only.')
|
||||||
@cli.argument('files', nargs='*', arg_only=True, type=normpath, completer=FilesCompleter('.c'), help='Filename(s) to format.')
|
@cli.argument('files', nargs='*', arg_only=True, help='Filename(s) to format.')
|
||||||
@cli.subcommand("Format C code according to QMK's style.", hidden=False if cli.config.user.developer else True)
|
@cli.subcommand('Pointer to the new command name: qmk format-c.', hidden=False if cli.config.user.developer else True)
|
||||||
def cformat(cli):
|
def cformat(cli):
|
||||||
"""Format C code according to QMK's style.
|
"""Pointer to the new command name: qmk format-c.
|
||||||
"""
|
"""
|
||||||
# Find the list of files to format
|
cli.log.warning('"qmk cformat" has been renamed to "qmk format-c". Please use the new command in the future.')
|
||||||
if cli.args.files:
|
argv = [sys.executable, *sys.argv]
|
||||||
files = list(filter_files(cli.args.files, cli.args.core_only))
|
argv[argv.index('cformat')] = 'format-c'
|
||||||
|
script_path = Path(argv[1])
|
||||||
|
script_path_exe = Path(f'{argv[1]}.exe')
|
||||||
|
|
||||||
if not files:
|
if not script_path.exists() and script_path_exe.exists():
|
||||||
cli.log.error('No C files in filelist: %s', ', '.join(map(str, cli.args.files)))
|
# For reasons I don't understand ".exe" is stripped from the script name on windows.
|
||||||
exit(0)
|
argv[1] = str(script_path_exe)
|
||||||
|
|
||||||
if cli.args.all_files:
|
return cli.run(argv, capture_output=False).returncode
|
||||||
cli.log.warning('Filenames passed with -a, only formatting: %s', ','.join(map(str, files)))
|
|
||||||
|
|
||||||
elif cli.args.all_files:
|
|
||||||
all_files = c_source_files(core_dirs)
|
|
||||||
files = list(filter_files(all_files, True))
|
|
||||||
|
|
||||||
else:
|
|
||||||
git_diff_cmd = ['git', 'diff', '--name-only', cli.args.base_branch, *core_dirs]
|
|
||||||
git_diff = cli.run(git_diff_cmd, stdin=DEVNULL)
|
|
||||||
|
|
||||||
if git_diff.returncode != 0:
|
|
||||||
cli.log.error("Error running %s", git_diff_cmd)
|
|
||||||
print(git_diff.stderr)
|
|
||||||
return git_diff.returncode
|
|
||||||
|
|
||||||
files = []
|
|
||||||
|
|
||||||
for file in git_diff.stdout.strip().split('\n'):
|
|
||||||
if not any([file.startswith(ignore) for ignore in ignored]):
|
|
||||||
if path.exists(file) and file.split('.')[-1] in c_file_suffixes:
|
|
||||||
files.append(file)
|
|
||||||
|
|
||||||
# Sanity check
|
|
||||||
if not files:
|
|
||||||
cli.log.error('No changed files detected. Use "qmk cformat -a" to format all core files')
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Run clang-format on the files we've found
|
|
||||||
if cli.args.dry_run:
|
|
||||||
return not find_diffs(files)
|
|
||||||
else:
|
|
||||||
return cformat_run(files)
|
|
||||||
|
|
5
lib/python/qmk/cli/doctor/__init__.py
Executable file
5
lib/python/qmk/cli/doctor/__init__.py
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
"""QMK Doctor
|
||||||
|
|
||||||
|
Check out the user's QMK environment and make sure it's ready to compile.
|
||||||
|
"""
|
||||||
|
from .main import doctor
|
|
@ -1,4 +1,4 @@
|
||||||
"""OS-agnostic helper functions
|
"""Check for specific programs.
|
||||||
"""
|
"""
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
import re
|
import re
|
||||||
|
@ -30,7 +30,7 @@ ESSENTIAL_BINARIES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def parse_gcc_version(version):
|
def _parse_gcc_version(version):
|
||||||
m = re.match(r"(\d+)(?:\.(\d+))?(?:\.(\d+))?", version)
|
m = re.match(r"(\d+)(?:\.(\d+))?(?:\.(\d+))?", version)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -40,7 +40,7 @@ def parse_gcc_version(version):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def check_arm_gcc_version():
|
def _check_arm_gcc_version():
|
||||||
"""Returns True if the arm-none-eabi-gcc version is not known to cause problems.
|
"""Returns True if the arm-none-eabi-gcc version is not known to cause problems.
|
||||||
"""
|
"""
|
||||||
if 'output' in ESSENTIAL_BINARIES['arm-none-eabi-gcc']:
|
if 'output' in ESSENTIAL_BINARIES['arm-none-eabi-gcc']:
|
||||||
|
@ -50,7 +50,7 @@ def check_arm_gcc_version():
|
||||||
return CheckStatus.OK # Right now all known arm versions are ok
|
return CheckStatus.OK # Right now all known arm versions are ok
|
||||||
|
|
||||||
|
|
||||||
def check_avr_gcc_version():
|
def _check_avr_gcc_version():
|
||||||
"""Returns True if the avr-gcc version is not known to cause problems.
|
"""Returns True if the avr-gcc version is not known to cause problems.
|
||||||
"""
|
"""
|
||||||
rc = CheckStatus.ERROR
|
rc = CheckStatus.ERROR
|
||||||
|
@ -60,7 +60,7 @@ def check_avr_gcc_version():
|
||||||
cli.log.info('Found avr-gcc version %s', version_number)
|
cli.log.info('Found avr-gcc version %s', version_number)
|
||||||
rc = CheckStatus.OK
|
rc = CheckStatus.OK
|
||||||
|
|
||||||
parsed_version = parse_gcc_version(version_number)
|
parsed_version = _parse_gcc_version(version_number)
|
||||||
if parsed_version['major'] > 8:
|
if parsed_version['major'] > 8:
|
||||||
cli.log.warning('{fg_yellow}We do not recommend avr-gcc newer than 8. Downgrading to 8.x is recommended.')
|
cli.log.warning('{fg_yellow}We do not recommend avr-gcc newer than 8. Downgrading to 8.x is recommended.')
|
||||||
rc = CheckStatus.WARNING
|
rc = CheckStatus.WARNING
|
||||||
|
@ -68,7 +68,7 @@ def check_avr_gcc_version():
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
|
|
||||||
def check_avrdude_version():
|
def _check_avrdude_version():
|
||||||
if 'output' in ESSENTIAL_BINARIES['avrdude']:
|
if 'output' in ESSENTIAL_BINARIES['avrdude']:
|
||||||
last_line = ESSENTIAL_BINARIES['avrdude']['output'].split('\n')[-2]
|
last_line = ESSENTIAL_BINARIES['avrdude']['output'].split('\n')[-2]
|
||||||
version_number = last_line.split()[2][:-1]
|
version_number = last_line.split()[2][:-1]
|
||||||
|
@ -77,7 +77,7 @@ def check_avrdude_version():
|
||||||
return CheckStatus.OK
|
return CheckStatus.OK
|
||||||
|
|
||||||
|
|
||||||
def check_dfu_util_version():
|
def _check_dfu_util_version():
|
||||||
if 'output' in ESSENTIAL_BINARIES['dfu-util']:
|
if 'output' in ESSENTIAL_BINARIES['dfu-util']:
|
||||||
first_line = ESSENTIAL_BINARIES['dfu-util']['output'].split('\n')[0]
|
first_line = ESSENTIAL_BINARIES['dfu-util']['output'].split('\n')[0]
|
||||||
version_number = first_line.split()[1]
|
version_number = first_line.split()[1]
|
||||||
|
@ -86,7 +86,7 @@ def check_dfu_util_version():
|
||||||
return CheckStatus.OK
|
return CheckStatus.OK
|
||||||
|
|
||||||
|
|
||||||
def check_dfu_programmer_version():
|
def _check_dfu_programmer_version():
|
||||||
if 'output' in ESSENTIAL_BINARIES['dfu-programmer']:
|
if 'output' in ESSENTIAL_BINARIES['dfu-programmer']:
|
||||||
first_line = ESSENTIAL_BINARIES['dfu-programmer']['output'].split('\n')[0]
|
first_line = ESSENTIAL_BINARIES['dfu-programmer']['output'].split('\n')[0]
|
||||||
version_number = first_line.split()[1]
|
version_number = first_line.split()[1]
|
||||||
|
@ -111,7 +111,7 @@ def check_binary_versions():
|
||||||
"""Check the versions of ESSENTIAL_BINARIES
|
"""Check the versions of ESSENTIAL_BINARIES
|
||||||
"""
|
"""
|
||||||
versions = []
|
versions = []
|
||||||
for check in (check_arm_gcc_version, check_avr_gcc_version, check_avrdude_version, check_dfu_util_version, check_dfu_programmer_version):
|
for check in (_check_arm_gcc_version, _check_avr_gcc_version, _check_avrdude_version, _check_dfu_util_version, _check_dfu_programmer_version):
|
||||||
versions.append(check())
|
versions.append(check())
|
||||||
return versions
|
return versions
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
"""OS-specific functions for: Linux
|
"""OS-specific functions for: Linux
|
||||||
"""
|
"""
|
||||||
from pathlib import Path
|
import platform
|
||||||
import shutil
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
from qmk.constants import QMK_FIRMWARE
|
from qmk.constants import QMK_FIRMWARE
|
||||||
from qmk.os_helpers import CheckStatus
|
from .check import CheckStatus
|
||||||
|
|
||||||
|
|
||||||
def _udev_rule(vid, pid=None, *args):
|
def _udev_rule(vid, pid=None, *args):
|
||||||
|
@ -138,3 +140,23 @@ def check_modem_manager():
|
||||||
"""(TODO): Add check for non-systemd systems
|
"""(TODO): Add check for non-systemd systems
|
||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def os_test_linux():
|
||||||
|
"""Run the Linux specific tests.
|
||||||
|
"""
|
||||||
|
# Don't bother with udev on WSL, for now
|
||||||
|
if 'microsoft' in platform.uname().release.lower():
|
||||||
|
cli.log.info("Detected {fg_cyan}Linux (WSL){fg_reset}.")
|
||||||
|
|
||||||
|
# https://github.com/microsoft/WSL/issues/4197
|
||||||
|
if QMK_FIRMWARE.as_posix().startswith("/mnt"):
|
||||||
|
cli.log.warning("I/O performance on /mnt may be extremely slow.")
|
||||||
|
return CheckStatus.WARNING
|
||||||
|
|
||||||
|
return CheckStatus.OK
|
||||||
|
else:
|
||||||
|
cli.log.info("Detected {fg_cyan}Linux{fg_reset}.")
|
||||||
|
from .linux import check_udev_rules
|
||||||
|
|
||||||
|
return check_udev_rules()
|
13
lib/python/qmk/cli/doctor/macos.py
Normal file
13
lib/python/qmk/cli/doctor/macos.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import platform
|
||||||
|
|
||||||
|
from milc import cli
|
||||||
|
|
||||||
|
from .check import CheckStatus
|
||||||
|
|
||||||
|
|
||||||
|
def os_test_macos():
|
||||||
|
"""Run the Mac specific tests.
|
||||||
|
"""
|
||||||
|
cli.log.info("Detected {fg_cyan}macOS %s{fg_reset}.", platform.mac_ver()[0])
|
||||||
|
|
||||||
|
return CheckStatus.OK
|
|
@ -7,9 +7,10 @@ from subprocess import DEVNULL
|
||||||
|
|
||||||
from milc import cli
|
from milc import cli
|
||||||
from milc.questions import yesno
|
from milc.questions import yesno
|
||||||
|
|
||||||
from qmk import submodules
|
from qmk import submodules
|
||||||
from qmk.constants import QMK_FIRMWARE
|
from qmk.constants import QMK_FIRMWARE
|
||||||
from qmk.os_helpers import CheckStatus, check_binaries, check_binary_versions, check_submodules, check_git_repo
|
from .check import CheckStatus, check_binaries, check_binary_versions, check_submodules, check_git_repo
|
||||||
|
|
||||||
|
|
||||||
def os_tests():
|
def os_tests():
|
||||||
|
@ -18,53 +19,19 @@ def os_tests():
|
||||||
platform_id = platform.platform().lower()
|
platform_id = platform.platform().lower()
|
||||||
|
|
||||||
if 'darwin' in platform_id or 'macos' in platform_id:
|
if 'darwin' in platform_id or 'macos' in platform_id:
|
||||||
|
from .macos import os_test_macos
|
||||||
return os_test_macos()
|
return os_test_macos()
|
||||||
elif 'linux' in platform_id:
|
elif 'linux' in platform_id:
|
||||||
|
from .linux import os_test_linux
|
||||||
return os_test_linux()
|
return os_test_linux()
|
||||||
elif 'windows' in platform_id:
|
elif 'windows' in platform_id:
|
||||||
|
from .windows import os_test_windows
|
||||||
return os_test_windows()
|
return os_test_windows()
|
||||||
else:
|
else:
|
||||||
cli.log.warning('Unsupported OS detected: %s', platform_id)
|
cli.log.warning('Unsupported OS detected: %s', platform_id)
|
||||||
return CheckStatus.WARNING
|
return CheckStatus.WARNING
|
||||||
|
|
||||||
|
|
||||||
def os_test_linux():
|
|
||||||
"""Run the Linux specific tests.
|
|
||||||
"""
|
|
||||||
# Don't bother with udev on WSL, for now
|
|
||||||
if 'microsoft' in platform.uname().release.lower():
|
|
||||||
cli.log.info("Detected {fg_cyan}Linux (WSL){fg_reset}.")
|
|
||||||
|
|
||||||
# https://github.com/microsoft/WSL/issues/4197
|
|
||||||
if QMK_FIRMWARE.as_posix().startswith("/mnt"):
|
|
||||||
cli.log.warning("I/O performance on /mnt may be extremely slow.")
|
|
||||||
return CheckStatus.WARNING
|
|
||||||
|
|
||||||
return CheckStatus.OK
|
|
||||||
else:
|
|
||||||
cli.log.info("Detected {fg_cyan}Linux{fg_reset}.")
|
|
||||||
from qmk.os_helpers.linux import check_udev_rules
|
|
||||||
|
|
||||||
return check_udev_rules()
|
|
||||||
|
|
||||||
|
|
||||||
def os_test_macos():
|
|
||||||
"""Run the Mac specific tests.
|
|
||||||
"""
|
|
||||||
cli.log.info("Detected {fg_cyan}macOS %s{fg_reset}.", platform.mac_ver()[0])
|
|
||||||
|
|
||||||
return CheckStatus.OK
|
|
||||||
|
|
||||||
|
|
||||||
def os_test_windows():
|
|
||||||
"""Run the Windows specific tests.
|
|
||||||
"""
|
|
||||||
win32_ver = platform.win32_ver()
|
|
||||||
cli.log.info("Detected {fg_cyan}Windows %s (%s){fg_reset}.", win32_ver[0], win32_ver[1])
|
|
||||||
|
|
||||||
return CheckStatus.OK
|
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('-y', '--yes', action='store_true', arg_only=True, help='Answer yes to all questions.')
|
@cli.argument('-y', '--yes', action='store_true', arg_only=True, help='Answer yes to all questions.')
|
||||||
@cli.argument('-n', '--no', action='store_true', arg_only=True, help='Answer no to all questions.')
|
@cli.argument('-n', '--no', action='store_true', arg_only=True, help='Answer no to all questions.')
|
||||||
@cli.subcommand('Basic QMK environment checks')
|
@cli.subcommand('Basic QMK environment checks')
|
14
lib/python/qmk/cli/doctor/windows.py
Normal file
14
lib/python/qmk/cli/doctor/windows.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import platform
|
||||||
|
|
||||||
|
from milc import cli
|
||||||
|
|
||||||
|
from .check import CheckStatus
|
||||||
|
|
||||||
|
|
||||||
|
def os_test_windows():
|
||||||
|
"""Run the Windows specific tests.
|
||||||
|
"""
|
||||||
|
win32_ver = platform.win32_ver()
|
||||||
|
cli.log.info("Detected {fg_cyan}Windows %s (%s){fg_reset}.", win32_ver[0], win32_ver[1])
|
||||||
|
|
||||||
|
return CheckStatus.OK
|
24
lib/python/qmk/cli/fileformat.py
Normal file → Executable file
24
lib/python/qmk/cli/fileformat.py
Normal file → Executable file
|
@ -1,13 +1,23 @@
|
||||||
"""Format files according to QMK's style.
|
"""Point people to the new command name.
|
||||||
"""
|
"""
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
|
@cli.subcommand('Pointer to the new command name: qmk format-text.', hidden=False if cli.config.user.developer else True)
|
||||||
@cli.subcommand("Format files according to QMK's style.", hidden=True)
|
|
||||||
def fileformat(cli):
|
def fileformat(cli):
|
||||||
"""Run several general formatting commands.
|
"""Pointer to the new command name: qmk format-text.
|
||||||
"""
|
"""
|
||||||
dos2unix = subprocess.run(['bash', '-c', 'git ls-files -z | xargs -0 dos2unix'], stdout=subprocess.DEVNULL)
|
cli.log.warning('"qmk fileformat" has been renamed to "qmk format-text". Please use the new command in the future.')
|
||||||
return dos2unix.returncode
|
argv = [sys.executable, *sys.argv]
|
||||||
|
argv[argv.index('fileformat')] = 'format-text'
|
||||||
|
script_path = Path(argv[1])
|
||||||
|
script_path_exe = Path(f'{argv[1]}.exe')
|
||||||
|
|
||||||
|
if not script_path.exists() and script_path_exe.exists():
|
||||||
|
# For reasons I don't understand ".exe" is stripped from the script name on windows.
|
||||||
|
argv[1] = str(script_path_exe)
|
||||||
|
|
||||||
|
return cli.run(argv, capture_output=False).returncode
|
||||||
|
|
137
lib/python/qmk/cli/format/c.py
Normal file
137
lib/python/qmk/cli/format/c.py
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
"""Format C code according to QMK's style.
|
||||||
|
"""
|
||||||
|
from os import path
|
||||||
|
from shutil import which
|
||||||
|
from subprocess import CalledProcessError, DEVNULL, Popen, PIPE
|
||||||
|
|
||||||
|
from argcomplete.completers import FilesCompleter
|
||||||
|
from milc import cli
|
||||||
|
|
||||||
|
from qmk.path import normpath
|
||||||
|
from qmk.c_parse import c_source_files
|
||||||
|
|
||||||
|
c_file_suffixes = ('c', 'h', 'cpp')
|
||||||
|
core_dirs = ('drivers', 'quantum', 'tests', 'tmk_core', 'platforms')
|
||||||
|
ignored = ('tmk_core/protocol/usb_hid', 'quantum/template', 'platforms/chibios')
|
||||||
|
|
||||||
|
|
||||||
|
def find_clang_format():
|
||||||
|
"""Returns the path to clang-format.
|
||||||
|
"""
|
||||||
|
for clang_version in range(20, 6, -1):
|
||||||
|
binary = f'clang-format-{clang_version}'
|
||||||
|
|
||||||
|
if which(binary):
|
||||||
|
return binary
|
||||||
|
|
||||||
|
return 'clang-format'
|
||||||
|
|
||||||
|
|
||||||
|
def find_diffs(files):
|
||||||
|
"""Run clang-format and diff it against a file.
|
||||||
|
"""
|
||||||
|
found_diffs = False
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
cli.log.debug('Checking for changes in %s', file)
|
||||||
|
clang_format = Popen([find_clang_format(), file], stdout=PIPE, stderr=PIPE, universal_newlines=True)
|
||||||
|
diff = cli.run(['diff', '-u', f'--label=a/{file}', f'--label=b/{file}', str(file), '-'], stdin=clang_format.stdout, capture_output=True)
|
||||||
|
|
||||||
|
if diff.returncode != 0:
|
||||||
|
print(diff.stdout)
|
||||||
|
found_diffs = True
|
||||||
|
|
||||||
|
return found_diffs
|
||||||
|
|
||||||
|
|
||||||
|
def cformat_run(files):
|
||||||
|
"""Spawn clang-format subprocess with proper arguments
|
||||||
|
"""
|
||||||
|
# Determine which version of clang-format to use
|
||||||
|
clang_format = [find_clang_format(), '-i']
|
||||||
|
|
||||||
|
try:
|
||||||
|
cli.run([*clang_format, *map(str, files)], check=True, capture_output=False, stdin=DEVNULL)
|
||||||
|
cli.log.info('Successfully formatted the C code.')
|
||||||
|
return True
|
||||||
|
|
||||||
|
except CalledProcessError as e:
|
||||||
|
cli.log.error('Error formatting C code!')
|
||||||
|
cli.log.debug('%s exited with returncode %s', e.cmd, e.returncode)
|
||||||
|
cli.log.debug('STDOUT:')
|
||||||
|
cli.log.debug(e.stdout)
|
||||||
|
cli.log.debug('STDERR:')
|
||||||
|
cli.log.debug(e.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def filter_files(files, core_only=False):
|
||||||
|
"""Yield only files to be formatted and skip the rest
|
||||||
|
"""
|
||||||
|
if core_only:
|
||||||
|
# Filter non-core files
|
||||||
|
for index, file in enumerate(files):
|
||||||
|
# The following statement checks each file to see if the file path is
|
||||||
|
# - in the core directories
|
||||||
|
# - not in the ignored directories
|
||||||
|
if not any(i in str(file) for i in core_dirs) or any(i in str(file) for i in ignored):
|
||||||
|
files[index] = None
|
||||||
|
cli.log.debug("Skipping non-core file %s, as '--core-only' is used.", file)
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
if file and file.name.split('.')[-1] in c_file_suffixes:
|
||||||
|
yield file
|
||||||
|
else:
|
||||||
|
cli.log.debug('Skipping file %s', file)
|
||||||
|
|
||||||
|
|
||||||
|
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Flag only, don't automatically format.")
|
||||||
|
@cli.argument('-b', '--base-branch', default='origin/master', help='Branch to compare to diffs to.')
|
||||||
|
@cli.argument('-a', '--all-files', arg_only=True, action='store_true', help='Format all core files.')
|
||||||
|
@cli.argument('--core-only', arg_only=True, action='store_true', help='Format core files only.')
|
||||||
|
@cli.argument('files', nargs='*', arg_only=True, type=normpath, completer=FilesCompleter('.c'), help='Filename(s) to format.')
|
||||||
|
@cli.subcommand("Format C code according to QMK's style.", hidden=False if cli.config.user.developer else True)
|
||||||
|
def format_c(cli):
|
||||||
|
"""Format C code according to QMK's style.
|
||||||
|
"""
|
||||||
|
# Find the list of files to format
|
||||||
|
if cli.args.files:
|
||||||
|
files = list(filter_files(cli.args.files, cli.args.core_only))
|
||||||
|
|
||||||
|
if not files:
|
||||||
|
cli.log.error('No C files in filelist: %s', ', '.join(map(str, cli.args.files)))
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
if cli.args.all_files:
|
||||||
|
cli.log.warning('Filenames passed with -a, only formatting: %s', ','.join(map(str, files)))
|
||||||
|
|
||||||
|
elif cli.args.all_files:
|
||||||
|
all_files = c_source_files(core_dirs)
|
||||||
|
files = list(filter_files(all_files, True))
|
||||||
|
|
||||||
|
else:
|
||||||
|
git_diff_cmd = ['git', 'diff', '--name-only', cli.args.base_branch, *core_dirs]
|
||||||
|
git_diff = cli.run(git_diff_cmd, stdin=DEVNULL)
|
||||||
|
|
||||||
|
if git_diff.returncode != 0:
|
||||||
|
cli.log.error("Error running %s", git_diff_cmd)
|
||||||
|
print(git_diff.stderr)
|
||||||
|
return git_diff.returncode
|
||||||
|
|
||||||
|
files = []
|
||||||
|
|
||||||
|
for file in git_diff.stdout.strip().split('\n'):
|
||||||
|
if not any([file.startswith(ignore) for ignore in ignored]):
|
||||||
|
if path.exists(file) and file.split('.')[-1] in c_file_suffixes:
|
||||||
|
files.append(file)
|
||||||
|
|
||||||
|
# Sanity check
|
||||||
|
if not files:
|
||||||
|
cli.log.error('No changed files detected. Use "qmk cformat -a" to format all core files')
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Run clang-format on the files we've found
|
||||||
|
if cli.args.dry_run:
|
||||||
|
return not find_diffs(files)
|
||||||
|
else:
|
||||||
|
return cformat_run(files)
|
|
@ -8,7 +8,7 @@ from jsonschema import ValidationError
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
from qmk.info import info_json
|
from qmk.info import info_json
|
||||||
from qmk.json_schema import json_load, keyboard_validate
|
from qmk.json_schema import json_load, validate
|
||||||
from qmk.json_encoders import InfoJSONEncoder, KeymapJSONEncoder
|
from qmk.json_encoders import InfoJSONEncoder, KeymapJSONEncoder
|
||||||
from qmk.path import normpath
|
from qmk.path import normpath
|
||||||
|
|
||||||
|
@ -23,14 +23,13 @@ def format_json(cli):
|
||||||
|
|
||||||
if cli.args.format == 'auto':
|
if cli.args.format == 'auto':
|
||||||
try:
|
try:
|
||||||
keyboard_validate(json_file)
|
validate(json_file, 'qmk.keyboard.v1')
|
||||||
json_encoder = InfoJSONEncoder
|
json_encoder = InfoJSONEncoder
|
||||||
|
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
cli.log.warning('File %s did not validate as a keyboard:\n\t%s', cli.args.json_file, e)
|
cli.log.warning('File %s did not validate as a keyboard:\n\t%s', cli.args.json_file, e)
|
||||||
cli.log.info('Treating %s as a keymap file.', cli.args.json_file)
|
cli.log.info('Treating %s as a keymap file.', cli.args.json_file)
|
||||||
json_encoder = KeymapJSONEncoder
|
json_encoder = KeymapJSONEncoder
|
||||||
|
|
||||||
elif cli.args.format == 'keyboard':
|
elif cli.args.format == 'keyboard':
|
||||||
json_encoder = InfoJSONEncoder
|
json_encoder = InfoJSONEncoder
|
||||||
elif cli.args.format == 'keymap':
|
elif cli.args.format == 'keymap':
|
||||||
|
|
26
lib/python/qmk/cli/format/python.py
Executable file
26
lib/python/qmk/cli/format/python.py
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
"""Format python code according to QMK's style.
|
||||||
|
"""
|
||||||
|
from subprocess import CalledProcessError, DEVNULL
|
||||||
|
|
||||||
|
from milc import cli
|
||||||
|
|
||||||
|
|
||||||
|
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually format.")
|
||||||
|
@cli.subcommand("Format python code according to QMK's style.", hidden=False if cli.config.user.developer else True)
|
||||||
|
def format_python(cli):
|
||||||
|
"""Format python code according to QMK's style.
|
||||||
|
"""
|
||||||
|
edit = '--diff' if cli.args.dry_run else '--in-place'
|
||||||
|
yapf_cmd = ['yapf', '-vv', '--recursive', edit, 'bin/qmk', 'lib/python']
|
||||||
|
try:
|
||||||
|
cli.run(yapf_cmd, check=True, capture_output=False, stdin=DEVNULL)
|
||||||
|
cli.log.info('Python code in `bin/qmk` and `lib/python` is correctly formatted.')
|
||||||
|
return True
|
||||||
|
|
||||||
|
except CalledProcessError:
|
||||||
|
if cli.args.dry_run:
|
||||||
|
cli.log.error('Python code in `bin/qmk` and `lib/python` incorrectly formatted!')
|
||||||
|
else:
|
||||||
|
cli.log.error('Error formatting python code!')
|
||||||
|
|
||||||
|
return False
|
27
lib/python/qmk/cli/format/text.py
Normal file
27
lib/python/qmk/cli/format/text.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
"""Ensure text files have the proper line endings.
|
||||||
|
"""
|
||||||
|
from subprocess import CalledProcessError
|
||||||
|
|
||||||
|
from milc import cli
|
||||||
|
|
||||||
|
|
||||||
|
@cli.subcommand("Ensure text files have the proper line endings.", hidden=True)
|
||||||
|
def format_text(cli):
|
||||||
|
"""Ensure text files have the proper line endings.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
file_list_cmd = cli.run(['git', 'ls-files', '-z'], check=True)
|
||||||
|
except CalledProcessError as e:
|
||||||
|
cli.log.error('Could not get file list: %s', e)
|
||||||
|
exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
cli.log.error('Unhandled exception: %s: %s', e.__class__.__name__, e)
|
||||||
|
cli.log.exception(e)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
dos2unix = cli.run(['xargs', '-0', 'dos2unix'], stdin=None, input=file_list_cmd.stdout)
|
||||||
|
|
||||||
|
if dos2unix.returncode != 0:
|
||||||
|
print(dos2unix.stderr)
|
||||||
|
|
||||||
|
return dos2unix.returncode
|
|
@ -1,26 +1,24 @@
|
||||||
"""Format python code according to QMK's style.
|
"""Point people to the new command name.
|
||||||
"""
|
"""
|
||||||
from subprocess import CalledProcessError, DEVNULL
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from milc import cli
|
from milc import cli
|
||||||
|
|
||||||
|
|
||||||
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Flag only, don't automatically format.")
|
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually format.")
|
||||||
@cli.subcommand("Format python code according to QMK's style.", hidden=False if cli.config.user.developer else True)
|
@cli.subcommand('Pointer to the new command name: qmk format-python.', hidden=False if cli.config.user.developer else True)
|
||||||
def pyformat(cli):
|
def pyformat(cli):
|
||||||
"""Format python code according to QMK's style.
|
"""Pointer to the new command name: qmk format-python.
|
||||||
"""
|
"""
|
||||||
edit = '--diff' if cli.args.dry_run else '--in-place'
|
cli.log.warning('"qmk pyformat" has been renamed to "qmk format-python". Please use the new command in the future.')
|
||||||
yapf_cmd = ['yapf', '-vv', '--recursive', edit, 'bin/qmk', 'lib/python']
|
argv = [sys.executable, *sys.argv]
|
||||||
try:
|
argv[argv.index('pyformat')] = 'format-python'
|
||||||
cli.run(yapf_cmd, check=True, capture_output=False, stdin=DEVNULL)
|
script_path = Path(argv[1])
|
||||||
cli.log.info('Python code in `bin/qmk` and `lib/python` is correctly formatted.')
|
script_path_exe = Path(f'{argv[1]}.exe')
|
||||||
return True
|
|
||||||
|
|
||||||
except CalledProcessError:
|
if not script_path.exists() and script_path_exe.exists():
|
||||||
if cli.args.dry_run:
|
# For reasons I don't understand ".exe" is stripped from the script name on windows.
|
||||||
cli.log.error('Python code in `bin/qmk` and `lib/python` incorrectly formatted!')
|
argv[1] = str(script_path_exe)
|
||||||
else:
|
|
||||||
cli.log.error('Error formatting python code!')
|
|
||||||
|
|
||||||
return False
|
return cli.run(argv, capture_output=False).returncode
|
||||||
|
|
|
@ -9,7 +9,7 @@ from milc import cli
|
||||||
|
|
||||||
from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS
|
from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS
|
||||||
from qmk.c_parse import find_layouts
|
from qmk.c_parse import find_layouts
|
||||||
from qmk.json_schema import deep_update, json_load, keyboard_validate, keyboard_api_validate
|
from qmk.json_schema import deep_update, json_load, validate
|
||||||
from qmk.keyboard import config_h, rules_mk
|
from qmk.keyboard import config_h, rules_mk
|
||||||
from qmk.keymap import list_keymaps
|
from qmk.keymap import list_keymaps
|
||||||
from qmk.makefile import parse_rules_mk_file
|
from qmk.makefile import parse_rules_mk_file
|
||||||
|
@ -66,7 +66,7 @@ def info_json(keyboard):
|
||||||
|
|
||||||
# Validate against the jsonschema
|
# Validate against the jsonschema
|
||||||
try:
|
try:
|
||||||
keyboard_api_validate(info_data)
|
validate(info_data, 'qmk.api.keyboard.v1')
|
||||||
|
|
||||||
except jsonschema.ValidationError as e:
|
except jsonschema.ValidationError as e:
|
||||||
json_path = '.'.join([str(p) for p in e.absolute_path])
|
json_path = '.'.join([str(p) for p in e.absolute_path])
|
||||||
|
@ -496,7 +496,7 @@ def merge_info_jsons(keyboard, info_data):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
keyboard_validate(new_info_data)
|
validate(new_info_data, 'qmk.keyboard.v1')
|
||||||
except jsonschema.ValidationError as e:
|
except jsonschema.ValidationError as e:
|
||||||
json_path = '.'.join([str(p) for p in e.absolute_path])
|
json_path = '.'.join([str(p) for p in e.absolute_path])
|
||||||
cli.log.error('Not including data from file: %s', info_file)
|
cli.log.error('Not including data from file: %s', info_file)
|
||||||
|
|
|
@ -24,9 +24,10 @@ def json_load(json_file):
|
||||||
|
|
||||||
def load_jsonschema(schema_name):
|
def load_jsonschema(schema_name):
|
||||||
"""Read a jsonschema file from disk.
|
"""Read a jsonschema file from disk.
|
||||||
|
|
||||||
FIXME(skullydazed/anyone): Refactor to make this a public function.
|
|
||||||
"""
|
"""
|
||||||
|
if Path(schema_name).exists():
|
||||||
|
return json_load(schema_name)
|
||||||
|
|
||||||
schema_path = Path(f'data/schemas/{schema_name}.jsonschema')
|
schema_path = Path(f'data/schemas/{schema_name}.jsonschema')
|
||||||
|
|
||||||
if not schema_path.exists():
|
if not schema_path.exists():
|
||||||
|
@ -35,28 +36,33 @@ def load_jsonschema(schema_name):
|
||||||
return json_load(schema_path)
|
return json_load(schema_path)
|
||||||
|
|
||||||
|
|
||||||
def keyboard_validate(data):
|
def create_validator(schema):
|
||||||
"""Validates data against the keyboard jsonschema.
|
"""Creates a validator for the given schema id.
|
||||||
"""
|
"""
|
||||||
schema = load_jsonschema('keyboard')
|
schema_store = {}
|
||||||
validator = jsonschema.Draft7Validator(schema).validate
|
|
||||||
|
|
||||||
return validator(data)
|
for schema_file in Path('data/schemas').glob('*.jsonschema'):
|
||||||
|
schema_data = load_jsonschema(schema_file)
|
||||||
|
if not isinstance(schema_data, dict):
|
||||||
|
cli.log.debug('Skipping schema file %s', schema_file)
|
||||||
|
continue
|
||||||
|
schema_store[schema_data['$id']] = schema_data
|
||||||
|
|
||||||
|
resolver = jsonschema.RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store)
|
||||||
|
|
||||||
|
return jsonschema.Draft7Validator(schema_store[schema], resolver=resolver).validate
|
||||||
|
|
||||||
|
|
||||||
def keyboard_api_validate(data):
|
def validate(data, schema):
|
||||||
"""Validates data against the api_keyboard jsonschema.
|
"""Validates data against a schema.
|
||||||
"""
|
"""
|
||||||
base = load_jsonschema('keyboard')
|
validator = create_validator(schema)
|
||||||
relative = load_jsonschema('api_keyboard')
|
|
||||||
resolver = jsonschema.RefResolver.from_schema(base)
|
|
||||||
validator = jsonschema.Draft7Validator(relative, resolver=resolver).validate
|
|
||||||
|
|
||||||
return validator(data)
|
return validator(data)
|
||||||
|
|
||||||
|
|
||||||
def deep_update(origdict, newdict):
|
def deep_update(origdict, newdict):
|
||||||
"""Update a dictionary in place, recursing to do a deep copy.
|
"""Update a dictionary in place, recursing to do a depth-first deep copy.
|
||||||
"""
|
"""
|
||||||
for key, value in newdict.items():
|
for key, value in newdict.items():
|
||||||
if isinstance(value, Mapping):
|
if isinstance(value, Mapping):
|
||||||
|
|
Loading…
Reference in a new issue