diff --git a/.github/workflows/api.yml b/.github/workflows/api.yml index a19667f97e7f..f0c49baf60bb 100644 --- a/.github/workflows/api.yml +++ b/.github/workflows/api.yml @@ -35,4 +35,4 @@ jobs: AWS_ACCESS_KEY_ID: ${{ secrets.SPACES_ACCESS_KEY }} AWS_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET_KEY }} AWS_S3_ENDPOINT: https://nyc3.digitaloceanspaces.com - SOURCE_DIR: 'api_data' + SOURCE_DIR: '.build/api_data' diff --git a/.github/workflows/develop_api.yml b/.github/workflows/develop_api.yml index f0098142c7bc..3eb6e53c20b7 100644 --- a/.github/workflows/develop_api.yml +++ b/.github/workflows/develop_api.yml @@ -35,4 +35,4 @@ jobs: AWS_ACCESS_KEY_ID: ${{ secrets.SPACES_ACCESS_KEY }} AWS_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET_KEY }} AWS_S3_ENDPOINT: https://nyc3.digitaloceanspaces.com - SOURCE_DIR: 'api_data' + SOURCE_DIR: '.build/api_data' diff --git a/api_data/_config.yml b/api_data/_config.yml deleted file mode 100644 index 277f1f2c510d..000000000000 --- a/api_data/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-cayman diff --git a/data/mappings/info_config.json b/data/mappings/info_config.json index cfe8807d4363..2121741d1996 100644 --- a/data/mappings/info_config.json +++ b/data/mappings/info_config.json @@ -3,7 +3,7 @@ { # Format: # : {"info_key": , ["value_type": ], ["to_json": ], ["to_c": ]} - # value_type: one of "array", "array.int", "bool", "int", "hex", "list", "mapping" + # value_type: one of "array", "array.int", "bool", "int", "hex", "list", "mapping", "str", "raw" # to_json: Default `true`. Set to `false` to exclude this mapping from info.json # to_c: Default `true`. Set to `false` to exclude this mapping from config.h # warn_duplicate: Default `true`. Set to `false` to turn off warning when a value exists in both places @@ -17,7 +17,7 @@ "DEVICE_VER": {"info_key": "usb.device_ver", "value_type": "hex"}, # TODO: Replace ^^^ with vvv #"DEVICE_VER": {"info_key": "usb.device_version", "value_type": "bcd_version"}, - "DESCRIPTION": {"info_key": "keyboard_folder", "to_json": false}, + "DESCRIPTION": {"info_key": "keyboard_folder", "value_type": "str", "to_json": false}, "DIODE_DIRECTION": {"info_key": "diode_direction"}, "FORCE_NKRO": {"info_key": "usb.force_nkro", "value_type": "bool"}, "DYNAMIC_KEYMAP_EEPROM_MAX_ADDR": {"info_key": "dynamic_keymap.eeprom_max_addr", "value_type": "int"}, diff --git a/data/mappings/info_rules.json b/data/mappings/info_rules.json index aea67e04c846..f03cadcd44f6 100644 --- a/data/mappings/info_rules.json +++ b/data/mappings/info_rules.json @@ -3,7 +3,7 @@ { # Format: # : {"info_key": , ["value_type": ], ["to_json": ], ["to_c": ]} - # value_type: one of "array", "array.int", "bool", "int", "list", "hex", "mapping" + # value_type: one of "array", "array.int", "bool", "int", "list", "hex", "mapping", "str", "raw" # to_json: Default `true`. Set to `false` to exclude this mapping from info.json # to_c: Default `true`. Set to `false` to exclude this mapping from rules.mk # warn_duplicate: Default `true`. Set to `false` to turn off warning when a value exists in both places @@ -20,6 +20,6 @@ "MOUSEKEY_ENABLE": {"info_key": "mouse_key.enabled", "value_type": "bool"}, "NO_USB_STARTUP_CHECK": {"info_key": "usb.no_startup_check", "value_type": "bool"}, "SPLIT_KEYBOARD": {"info_key": "split.enabled", "value_type": "bool"}, - "SPLIT_TRANSPORT": {"info_key": "split.transport.protocol", "value_type": "str", "to_c": false}, + "SPLIT_TRANSPORT": {"info_key": "split.transport.protocol", "to_c": false}, "WAIT_FOR_USB": {"info_key": "usb.wait_for", "value_type": "bool"} } diff --git a/api_data/readme.md b/data/templates/api/readme.md similarity index 100% rename from api_data/readme.md rename to data/templates/api/readme.md diff --git a/docs/data_driven_config.md b/docs/data_driven_config.md index 38fb5dbf1445..cdcf21a19c5b 100644 --- a/docs/data_driven_config.md +++ b/docs/data_driven_config.md @@ -44,7 +44,7 @@ In other cases you should group like options together in an `object`. This is pa In most cases you can add a simple mapping. These are maintained as JSON files in `data/mappings/info_config.json` and `data/mappings/info_rules.json`, and control mapping for `config.h` and `rules.mk`, respectively. Each mapping is keyed by the `config.h` or `rules.mk` variable, and the value is a hash with the following keys: * `info_key`: (required) The location within `info.json` for this value. See below. -* `value_type`: (optional) Default `str`. The format for this variable's value. See below. +* `value_type`: (optional) Default `raw`. The format for this variable's value. See below. * `to_json`: (optional) Default `true`. Set to `false` to exclude this mapping from info.json * `to_c`: (optional) Default `true`. Set to `false` to exclude this mapping from config.h * `warn_duplicate`: (optional) Default `true`. Set to `false` to turn off warning when a value exists in both places @@ -57,7 +57,7 @@ Under the hood we use [Dotty Dict](https://dotty-dict.readthedocs.io/en/latest/) #### Value Types -By default we treat all values as simple strings. If your value is more complex you can use one of these types to intelligently parse the data: +By default we treat all values as unquoted "raw" data. If your value is more complex you can use one of these types to intelligently parse the data: * `array`: A comma separated array of strings * `array.int`: A comma separated array of integers @@ -65,6 +65,7 @@ By default we treat all values as simple strings. If your value is more complex * `hex`: A number formatted as hex * `list`: A space separate array of strings * `mapping`: A hash of key/value pairs +* `str`: A quoted string literal ### Add code to extract it diff --git a/docs/feature_unicode.md b/docs/feature_unicode.md index 6c3e2a1a2fba..bced419a03fe 100644 --- a/docs/feature_unicode.md +++ b/docs/feature_unicode.md @@ -230,17 +230,6 @@ send_unicode_string("(ノಠ痊ಠ)ノ彡┻━┻"); Example uses include sending Unicode strings when a key is pressed, as described in [Macros](feature_macros.md). -### `send_unicode_hex_string()` (Deprecated) - -Similar to `send_unicode_string()`, but the characters are represented by their Unicode code points, written in hexadecimal and separated by spaces. For example, the table flip above would be achieved with: - -```c -send_unicode_hex_string("0028 30CE 0CA0 75CA 0CA0 0029 30CE 5F61 253B 2501 253B"); -``` - -An easy way to convert your Unicode string to this format is to use [this site](https://r12a.github.io/app-conversion/) and take the result in the "Hex/UTF-32" section. - - ## Additional Language Support In `quantum/keymap_extras`, you'll see various language files — these work the same way as the ones for alternative layouts such as Colemak or BÉPO. When you include one of these language headers, you gain access to keycodes specific to that language / national layout. Such keycodes are defined by a 2-letter country/language code, followed by an underscore and a 4-letter abbreviation of the character to which the key corresponds. For example, including `keymap_french.h` and using `FR_UGRV` in your keymap will output `ù` when typed on a system with a native French AZERTY layout. diff --git a/docs/ja/feature_unicode.md b/docs/ja/feature_unicode.md index bfcb866ce1b0..2158678f3c48 100644 --- a/docs/ja/feature_unicode.md +++ b/docs/ja/feature_unicode.md @@ -233,17 +233,6 @@ send_unicode_string("(ノಠ痊ಠ)ノ彡┻━┻"); 使用例には、[Macros](ja/feature_macros.md) で説明されているように、キーが押された時に Unicode 文字列を送信することが含まれます。 -### `send_unicode_hex_string()` - -`send_unicode_string()` に似ていますが、文字は Unicode コードポイントで表され、16進数で記述され、空白で区切られています。例えば、上記のちゃぶ台返しは以下で表されます: - -```c -send_unicode_hex_string("0028 30CE 0CA0 75CA 0CA0 0029 30CE 5F61 253B 2501 253B"); -``` - -[このサイト](https://r12a.github.io/app-conversion/)で結果を "Hex/UTF-32" で受け取ることで、Unicode 文字列をこの形式に簡単に変換できます。 - - ## 追加の言語サポート `quantum/keymap_extras` には、様々な言語ファイルがあります — これらは Colemak または BÉPO のような代替レイアウトのファイルと同じように動作します。これらの言語ヘッダのいずれかを `#include` すると、その言語/国のレイアウトに固有のキーコードにアクセスできます。このようなキーコードは、2文字の国/言語コードの後に、アンダースコアとキーが対応する4文字の略語が続くことで定義されます。例えば、キーマップに `keymap_french.h` を含め、`FR_UGRV` を使うと、ネイティブのフランス語 AZERTY レイアウトを使うシステムで入力すると、`ù` が出力されます。 diff --git a/keyboards/sowbug/68keys/config.h b/keyboards/sowbug/68keys/config.h index 0aad9a457470..0721302dbe1e 100644 --- a/keyboards/sowbug/68keys/config.h +++ b/keyboards/sowbug/68keys/config.h @@ -26,7 +26,6 @@ #define DEVICE_VER 0x0001 #define MANUFACTURER github.com/sowbug #define PRODUCT 68-key keyboard -#define DESCRIPTION A 68-key keyboard based on 68keys.io // key matrix size #define MATRIX_ROWS 5 diff --git a/keyboards/sowbug/ansi_tkl/config.h b/keyboards/sowbug/ansi_tkl/config.h index 505453b72b55..44e82bbac734 100644 --- a/keyboards/sowbug/ansi_tkl/config.h +++ b/keyboards/sowbug/ansi_tkl/config.h @@ -26,7 +26,6 @@ #define DEVICE_VER 0x0001 #define MANUFACTURER github.com/sowbug #define PRODUCT ANSI TKL -#define DESCRIPTION A tenkeyless ANSI-layout keyboard // key matrix size #define MATRIX_ROWS 6 diff --git a/keyboards/unicomp/spacesaver_m_pre_2013/overnumpad_1xb/config.h b/keyboards/unicomp/spacesaver_m_pre_2013/overnumpad_1xb/config.h index 7bd5b224dff1..597d287b077c 100644 --- a/keyboards/unicomp/spacesaver_m_pre_2013/overnumpad_1xb/config.h +++ b/keyboards/unicomp/spacesaver_m_pre_2013/overnumpad_1xb/config.h @@ -23,7 +23,6 @@ #define DEVICE_VER 0x0001 #define MANUFACTURER Unicomp/Purdea Andrei #define PRODUCT Unicomp Spacesaver M -#define DESCRIPTION QMK firmware for the Unicomp Spacesaver M keyboard with a replacement Overnumpad controller #define SERIAL_NUMBER "purdea.ro:overnumpad_controller" /* key matrix size */ diff --git a/keyboards/xelus/ninjin/config.h b/keyboards/xelus/ninjin/config.h index cbaca37b5edc..4dd40210a66a 100644 --- a/keyboards/xelus/ninjin/config.h +++ b/keyboards/xelus/ninjin/config.h @@ -22,7 +22,6 @@ #define DEVICE_VER 0x0001 #define MANUFACTURER Xelus #define PRODUCT Ninjin -#define DESCRIPTION Ninjin /* key matrix size */ #define MATRIX_ROWS 6 diff --git a/lib/python/qmk/cli/generate/api.py b/lib/python/qmk/cli/generate/api.py index 285bd90eb560..0596b3f22b50 100755 --- a/lib/python/qmk/cli/generate/api.py +++ b/lib/python/qmk/cli/generate/api.py @@ -1,7 +1,7 @@ """This script automates the generation of the QMK API data. """ from pathlib import Path -from shutil import copyfile +import shutil import json from milc import cli @@ -12,28 +12,42 @@ from qmk.json_schema import json_load from qmk.keyboard import find_readme, list_keyboards +TEMPLATE_PATH = Path('data/templates/api/') +BUILD_API_PATH = Path('.build/api_data/') + @cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't write the data to disk.") +@cli.argument('-f', '--filter', arg_only=True, action='append', default=[], help="Filter the list of keyboards based on partial name matches the supplied value. May be passed multiple times.") @cli.subcommand('Creates a new keymap for the keyboard of your choosing', hidden=False if cli.config.user.developer else True) def generate_api(cli): """Generates the QMK API data. """ - api_data_dir = Path('api_data') - v1_dir = api_data_dir / 'v1' + if BUILD_API_PATH.exists(): + shutil.rmtree(BUILD_API_PATH) + + shutil.copytree(TEMPLATE_PATH, BUILD_API_PATH) + + v1_dir = BUILD_API_PATH / 'v1' keyboard_all_file = v1_dir / 'keyboards.json' # A massive JSON containing everything keyboard_list_file = v1_dir / 'keyboard_list.json' # A simple list of keyboard targets keyboard_aliases_file = v1_dir / 'keyboard_aliases.json' # A list of historical keyboard names and their new name keyboard_metadata_file = v1_dir / 'keyboard_metadata.json' # All the data configurator/via needs for initialization usb_file = v1_dir / 'usb.json' # A mapping of USB VID/PID -> keyboard target - if not api_data_dir.exists(): - api_data_dir.mkdir() + # Filter down when required + keyboard_list = list_keyboards() + if cli.args.filter: + kb_list = [] + for keyboard_name in keyboard_list: + if any(i in keyboard_name for i in cli.args.filter): + kb_list.append(keyboard_name) + keyboard_list = kb_list kb_all = {} usb_list = {} # Generate and write keyboard specific JSON files - for keyboard_name in list_keyboards(): + for keyboard_name in keyboard_list: kb_all[keyboard_name] = info_json(keyboard_name) keyboard_dir = v1_dir / 'keyboards' / keyboard_name keyboard_info = keyboard_dir / 'info.json' @@ -47,7 +61,7 @@ def generate_api(cli): cli.log.debug('Wrote file %s', keyboard_info) if keyboard_readme_src: - copyfile(keyboard_readme_src, keyboard_readme) + shutil.copyfile(keyboard_readme_src, keyboard_readme) cli.log.debug('Copied %s -> %s', keyboard_readme_src, keyboard_readme) if 'usb' in kb_all[keyboard_name]: diff --git a/lib/python/qmk/cli/generate/config_h.py b/lib/python/qmk/cli/generate/config_h.py index 24bbbdf51726..340ed1043678 100755 --- a/lib/python/qmk/cli/generate/config_h.py +++ b/lib/python/qmk/cli/generate/config_h.py @@ -82,7 +82,7 @@ def generate_config_items(kb_info_json, config_h_lines): for config_key, info_dict in info_config_map.items(): info_key = info_dict['info_key'] - key_type = info_dict.get('value_type', 'str') + key_type = info_dict.get('value_type', 'raw') to_config = info_dict.get('to_config', True) if not to_config: @@ -110,6 +110,11 @@ def generate_config_items(kb_info_json, config_h_lines): config_h_lines.append(f'#ifndef {key}') config_h_lines.append(f'# define {key} {value}') config_h_lines.append(f'#endif // {key}') + elif key_type == 'str': + config_h_lines.append('') + config_h_lines.append(f'#ifndef {config_key}') + config_h_lines.append(f'# define {config_key} "{config_value}"') + config_h_lines.append(f'#endif // {config_key}') elif key_type == 'bcd_version': (major, minor, revision) = config_value.split('.') config_h_lines.append('') @@ -200,7 +205,7 @@ def generate_config_h(cli): cli.args.output.parent.mkdir(parents=True, exist_ok=True) if cli.args.output.exists(): cli.args.output.replace(cli.args.output.parent / (cli.args.output.name + '.bak')) - cli.args.output.write_text(config_h) + cli.args.output.write_text(config_h, encoding='utf-8') if not cli.args.quiet: cli.log.info('Wrote info_config.h to %s.', cli.args.output) diff --git a/lib/python/qmk/cli/generate/rules_mk.py b/lib/python/qmk/cli/generate/rules_mk.py index ce824f6378e6..a1b10cc945a9 100755 --- a/lib/python/qmk/cli/generate/rules_mk.py +++ b/lib/python/qmk/cli/generate/rules_mk.py @@ -19,7 +19,7 @@ def process_mapping_rule(kb_info_json, rules_key, info_dict): return None info_key = info_dict['info_key'] - key_type = info_dict.get('value_type', 'str') + key_type = info_dict.get('value_type', 'raw') try: rules_value = kb_info_json[info_key] @@ -32,6 +32,8 @@ def process_mapping_rule(kb_info_json, rules_key, info_dict): return f'{rules_key} ?= {"yes" if rules_value else "no"}' elif key_type == 'mapping': return '\n'.join([f'{key} ?= {value}' for key, value in rules_value.items()]) + elif key_type == 'str': + return f'{rules_key} ?= "{rules_value}"' return f'{rules_key} ?= {rules_value}' diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py index b86eaa059f11..c399a9f32198 100644 --- a/lib/python/qmk/info.py +++ b/lib/python/qmk/info.py @@ -411,7 +411,7 @@ def _extract_config_h(info_data): for config_key, info_dict in info_config_map.items(): info_key = info_dict['info_key'] - key_type = info_dict.get('value_type', 'str') + key_type = info_dict.get('value_type', 'raw') try: if config_key in config_c and info_dict.get('to_json', True): @@ -443,6 +443,9 @@ def _extract_config_h(info_data): elif key_type == 'int': dotty_info[info_key] = int(config_c[config_key]) + elif key_type == 'str': + dotty_info[info_key] = config_c[config_key].strip('"') + elif key_type == 'bcd_version': major = int(config_c[config_key][2:4]) minor = int(config_c[config_key][4]) @@ -491,7 +494,7 @@ def _extract_rules_mk(info_data): for rules_key, info_dict in info_rules_map.items(): info_key = info_dict['info_key'] - key_type = info_dict.get('value_type', 'str') + key_type = info_dict.get('value_type', 'raw') try: if rules_key in rules and info_dict.get('to_json', True): @@ -523,6 +526,9 @@ def _extract_rules_mk(info_data): elif key_type == 'int': dotty_info[info_key] = int(rules[rules_key]) + elif key_type == 'str': + dotty_info[info_key] = rules[rules_key].strip('"') + else: dotty_info[info_key] = rules[rules_key] diff --git a/lib/python/qmk/tests/test_cli_commands.py b/lib/python/qmk/tests/test_cli_commands.py index 55e69175e64a..d40d4bf57394 100644 --- a/lib/python/qmk/tests/test_cli_commands.py +++ b/lib/python/qmk/tests/test_cli_commands.py @@ -244,7 +244,7 @@ def test_clean(): def test_generate_api(): - result = check_subcommand('generate-api', '--dry-run') + result = check_subcommand('generate-api', '--dry-run', '--filter', 'handwired/pytest') check_returncode(result) @@ -259,7 +259,7 @@ def test_generate_config_h(): result = check_subcommand('generate-config-h', '-kb', 'handwired/pytest/basic') check_returncode(result) assert '# define DEVICE_VER 0x0001' in result.stdout - assert '# define DESCRIPTION handwired/pytest/basic' in result.stdout + assert '# define DESCRIPTION "handwired/pytest/basic"' in result.stdout assert '# define DIODE_DIRECTION COL2ROW' in result.stdout assert '# define MANUFACTURER none' in result.stdout assert '# define PRODUCT pytest' in result.stdout diff --git a/platforms/avr/platform.mk b/platforms/avr/platform.mk index 4d9cafaeef4a..9f304d2e209d 100644 --- a/platforms/avr/platform.mk +++ b/platforms/avr/platform.mk @@ -18,6 +18,13 @@ COMPILEFLAGS += -ffunction-sections COMPILEFLAGS += -fdata-sections COMPILEFLAGS += -fpack-struct COMPILEFLAGS += -fshort-enums +COMPILEFLAGS += -mcall-prologues + +# Linker relaxation is only possible if +# link time optimizations are not enabled. +ifeq ($(strip $(LTO_ENABLE)), no) + COMPILEFLAGS += -mrelax +endif ASFLAGS += $(AVR_ASFLAGS) @@ -28,7 +35,7 @@ CFLAGS += -fno-strict-aliasing CXXFLAGS += $(COMPILEFLAGS) CXXFLAGS += -fno-exceptions -std=c++11 -LDFLAGS +=-Wl,--gc-sections +LDFLAGS += -Wl,--gc-sections OPT_DEFS += -DF_CPU=$(F_CPU)UL diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c index 46b77e14bae5..2606ea1f3720 100644 --- a/quantum/process_keycode/process_unicode_common.c +++ b/quantum/process_keycode/process_unicode_common.c @@ -16,8 +16,6 @@ #include "process_unicode_common.h" #include "eeprom.h" -#include -#include unicode_config_t unicode_config; uint8_t unicode_saved_mods; @@ -231,37 +229,6 @@ void register_unicode(uint32_t code_point) { unicode_input_finish(); } -// clang-format off - -void send_unicode_hex_string(const char *str) { - if (!str) { - return; - } - - while (*str) { - // Find the next code point (token) in the string - for (; *str == ' '; str++); // Skip leading spaces - size_t n = strcspn(str, " "); // Length of the current token - char code_point[n+1]; - strncpy(code_point, str, n); // Copy token into buffer - code_point[n] = '\0'; // Make sure it's null-terminated - - // Normalize the code point: make all hex digits lowercase - for (char *p = code_point; *p; p++) { - *p = tolower((unsigned char)*p); - } - - // Send the code point as a Unicode input string - unicode_input_start(); - send_string(code_point); - unicode_input_finish(); - - str += n; // Move to the first ' ' (or '\0') after the current token - } -} - -// clang-format on - // Borrowed from https://nullprogram.com/blog/2017/10/06/ static const char *decode_utf8(const char *str, int32_t *code_point) { const char *next; diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h index 1a6607c757d6..8a4494c9395c 100644 --- a/quantum/process_keycode/process_unicode_common.h +++ b/quantum/process_keycode/process_unicode_common.h @@ -90,7 +90,6 @@ void register_hex(uint16_t hex); void register_hex32(uint32_t hex); void register_unicode(uint32_t code_point); -void send_unicode_hex_string(const char *str); void send_unicode_string(const char *str); bool process_unicode_common(uint16_t keycode, keyrecord_t *record); diff --git a/readme.md b/readme.md index 5649ddfa097a..63b483c74474 100644 --- a/readme.md +++ b/readme.md @@ -1,3 +1,7 @@ +# This is the `develop` branch! + +See the [Breaking Changes](https://docs.qmk.fm/#/breaking_changes) document for more information. + # Quantum Mechanical Keyboard Firmware [![Current Version](https://img.shields.io/github/tag/qmk/qmk_firmware.svg)](https://github.com/qmk/qmk_firmware/tags)