|
33 | 33 |
|
34 | 34 | from milc import cli
|
35 | 35 |
|
36 |
| -import qmk.path |
| 36 | +from qmk.commands import dump_lines |
| 37 | +from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE |
37 | 38 | from qmk.keyboard import keyboard_completer, keyboard_folder
|
38 | 39 | from qmk.keymap import keymap_completer, locate_keymap
|
| 40 | +from qmk.path import normpath |
39 | 41 |
|
40 | 42 | KC_A = 4
|
41 | 43 | KC_SPC = 0x2c
|
@@ -63,9 +65,10 @@ def parse_file(file_name: str) -> List[Tuple[str, str]]:
|
63 | 65 | try:
|
64 | 66 | from english_words import english_words_lower_alpha_set as correct_words
|
65 | 67 | except ImportError:
|
66 |
| - cli.echo('Autocorrection will falsely trigger when a typo is a substring of a correctly spelled word.') |
67 |
| - cli.echo('To check for this, install the english_words package and rerun this script:') |
68 |
| - cli.echo(' {fg_cyan}python3 -m pip install english_words') |
| 68 | + if not cli.args.quiet: |
| 69 | + cli.echo('Autocorrection will falsely trigger when a typo is a substring of a correctly spelled word.') |
| 70 | + cli.echo('To check for this, install the english_words package and rerun this script:') |
| 71 | + cli.echo(' {fg_cyan}python3 -m pip install english_words') |
69 | 72 | # Use a minimal word list as a fallback.
|
70 | 73 | correct_words = ('information', 'available', 'international', 'language', 'loosest', 'reference', 'wealthier', 'entertainment', 'association', 'provides', 'technology', 'statehood')
|
71 | 74 |
|
@@ -232,58 +235,51 @@ def encode_link(link: Dict[str, Any]) -> List[int]:
|
232 | 235 | return [byte_offset & 255, byte_offset >> 8]
|
233 | 236 |
|
234 | 237 |
|
235 |
| -def write_generated_code(autocorrections: List[Tuple[str, str]], data: List[int], file_name: str) -> None: |
236 |
| - """Writes autocorrection data as generated C code to `file_name`. |
237 |
| - Args: |
238 |
| - autocorrections: List of (typo, correction) tuples. |
239 |
| - data: List of ints in 0-255, the serialized trie. |
240 |
| - file_name: String, path of the output C file. |
241 |
| - """ |
242 |
| - assert all(0 <= b <= 255 for b in data) |
243 |
| - |
244 |
| - def typo_len(e: Tuple[str, str]) -> int: |
245 |
| - return len(e[0]) |
| 238 | +def typo_len(e: Tuple[str, str]) -> int: |
| 239 | + return len(e[0]) |
246 | 240 |
|
247 |
| - min_typo = min(autocorrections, key=typo_len)[0] |
248 |
| - max_typo = max(autocorrections, key=typo_len)[0] |
249 |
| - generated_code = ''.join([ |
250 |
| - '// Generated code.\n\n', f'// Autocorrection dictionary ({len(autocorrections)} entries):\n', ''.join(sorted(f'// {typo:<{len(max_typo)}} -> {correction}\n' for typo, correction in autocorrections)), |
251 |
| - f'\n#define AUTOCORRECT_MIN_LENGTH {len(min_typo)} // "{min_typo}"\n', f'#define AUTOCORRECT_MAX_LENGTH {len(max_typo)} // "{max_typo}"\n\n', f'#define DICTIONARY_SIZE {len(data)}\n\n', |
252 |
| - textwrap.fill('static const uint8_t autocorrect_data[DICTIONARY_SIZE] PROGMEM = {%s};' % (', '.join(map(str, data))), width=120, subsequent_indent=' '), '\n\n' |
253 |
| - ]) |
254 | 241 |
|
255 |
| - with open(file_name, 'wt') as f: |
256 |
| - f.write(generated_code) |
| 242 | +def to_hex(b: int) -> str: |
| 243 | + return f'0x{b:02X}' |
257 | 244 |
|
258 | 245 |
|
259 |
| -@cli.argument('filename', default='autocorrect_dict.txt', help='The autocorrection database file') |
| 246 | +@cli.argument('filename', type=normpath, help='The autocorrection database file') |
260 | 247 | @cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.')
|
261 | 248 | @cli.argument('-km', '--keymap', completer=keymap_completer, help='The keymap to build a firmware for. Ignored when a configurator export is supplied.')
|
262 |
| -@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to') |
| 249 | +@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') |
| 250 | +@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") |
263 | 251 | @cli.subcommand('Generate the autocorrection data file from a dictionary file.')
|
264 | 252 | def generate_autocorrect_data(cli):
|
265 | 253 | autocorrections = parse_file(cli.args.filename)
|
266 | 254 | trie = make_trie(autocorrections)
|
267 | 255 | data = serialize_trie(autocorrections, trie)
|
268 |
| - # Environment processing |
269 |
| - if cli.args.output == '-': |
270 |
| - cli.args.output = None |
271 | 256 |
|
272 |
| - if cli.args.output: |
273 |
| - cli.args.output.parent.mkdir(parents=True, exist_ok=True) |
274 |
| - cli.log.info('Creating autocorrect database at {fg_cyan}%s', cli.args.output) |
275 |
| - write_generated_code(autocorrections, data, cli.args.output) |
| 257 | + current_keyboard = cli.args.keyboard or cli.config.user.keyboard or cli.config.generate_autocorrect_data.keyboard |
| 258 | + current_keymap = cli.args.keymap or cli.config.user.keymap or cli.config.generate_autocorrect_data.keymap |
| 259 | + |
| 260 | + if current_keyboard and current_keymap: |
| 261 | + cli.args.output = locate_keymap(current_keyboard, current_keymap).parent / 'autocorrect_data.h' |
276 | 262 |
|
277 |
| - else: |
278 |
| - current_keyboard = cli.args.keyboard or cli.config.user.keyboard or cli.config.generate_autocorrect_data.keyboard |
279 |
| - current_keymap = cli.args.keymap or cli.config.user.keymap or cli.config.generate_autocorrect_data.keymap |
| 263 | + assert all(0 <= b <= 255 for b in data) |
280 | 264 |
|
281 |
| - if current_keyboard and current_keymap: |
282 |
| - filename = locate_keymap(current_keyboard, current_keymap).parent / 'autocorrect_data.h' |
283 |
| - cli.log.info('Creating autocorrect database at {fg_cyan}%s', filename) |
284 |
| - write_generated_code(autocorrections, data, filename) |
| 265 | + min_typo = min(autocorrections, key=typo_len)[0] |
| 266 | + max_typo = max(autocorrections, key=typo_len)[0] |
285 | 267 |
|
286 |
| - else: |
287 |
| - write_generated_code(autocorrections, data, 'autocorrect_data.h') |
| 268 | + # Build the autocorrect_data.h file. |
| 269 | + autocorrect_data_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', ''] |
288 | 270 |
|
289 |
| - cli.log.info('Processed %d autocorrection entries to table with %d bytes.', len(autocorrections), len(data)) |
| 271 | + autocorrect_data_h_lines.append(f'// Autocorrection dictionary ({len(autocorrections)} entries):') |
| 272 | + for typo, correction in autocorrections: |
| 273 | + autocorrect_data_h_lines.append(f'// {typo:<{len(max_typo)}} -> {correction}') |
| 274 | + |
| 275 | + autocorrect_data_h_lines.append('') |
| 276 | + autocorrect_data_h_lines.append(f'#define AUTOCORRECT_MIN_LENGTH {len(min_typo)} // "{min_typo}"') |
| 277 | + autocorrect_data_h_lines.append(f'#define AUTOCORRECT_MAX_LENGTH {len(max_typo)} // "{max_typo}"') |
| 278 | + autocorrect_data_h_lines.append(f'#define DICTIONARY_SIZE {len(data)}') |
| 279 | + autocorrect_data_h_lines.append('') |
| 280 | + autocorrect_data_h_lines.append('static const uint8_t autocorrect_data[DICTIONARY_SIZE] PROGMEM = {') |
| 281 | + autocorrect_data_h_lines.append(textwrap.fill(' %s' % (', '.join(map(to_hex, data))), width=100, subsequent_indent=' ')) |
| 282 | + autocorrect_data_h_lines.append('};') |
| 283 | + |
| 284 | + # Show the results |
| 285 | + dump_lines(cli.args.output, autocorrect_data_h_lines, cli.args.quiet) |
0 commit comments