Conversation
|
|
||
| static uint8_t typo_buffer[AUTOCORRECT_MAX_LENGTH] = {KC_SPC}; | ||
| static uint8_t typo_buffer_size = 1; | ||
| #ifdef AUTOCORRECT_MULTI_BANK |
There was a problem hiding this comment.
Not sure this is the best way to handle it, but:
| #ifdef AUTOCORRECT_MULTI_BANK | |
| #if defined(AUTOCORRECT_MULTI_BANK) && __has_include("autocorrect_data_alt.h") |
There was a problem hiding this comment.
That's closer to what the other guard was, so I've made the change, but I don't know enough C to be sure which is preferred
drashna
left a comment
There was a problem hiding this comment.
"dual bank" seems more accurate, than "multibank".
getreuer
left a comment
There was a problem hiding this comment.
Thank you for your contribution!
docs/feature_autocorrect.md
Outdated
| useful for bilingual users or for running context-specific rulesets. | ||
| `QK_AUTOCORRECT_BANK_TOGGLE` can then be used to toggle the active dictionary and persist the selection to eeprom. | ||
|
|
||
| To use this feature, `autocorrect_data_alt.h` should be generated using the flag `-a`, which constructs an alternate dictionary with appropriately named constants |
There was a problem hiding this comment.
Nit: The sentence is missing a period . at the end.
|
|
||
| file_name = 'autocorrect_data_alt.h' if cli.args.alternate else 'autocorrect_data.h' | ||
| defines_suffix = '_ALT' if cli.args.alternate else '' | ||
| static_suffix = '_alt' if cli.args.alternate else '' |
There was a problem hiding this comment.
The existing code is fine. But to code golf this a bit, it would arguably be simpler to define only
suffix = '_ALT' if cli.args.alternate else ''then use {suffix.lower()} in the one occurrence below where the lowercase version of the suffix is needed.
| static uint8_t typo_buffer_size = 1; | ||
| #ifdef AUTOCORRECT_MULTI_BANK | ||
| # include "autocorrect_data_alt.h" | ||
| # pragma message "Autocorrect is using multibank." |
There was a problem hiding this comment.
Since AUTOCORRECT_MULTI_BANK is an opt-in feature, it seems superfluous and a bit spammy to have a pragma message that it is enabled. I'd remove it.
| #ifdef AUTOCORRECT_MULTI_BANK | ||
| # include "autocorrect_data_alt.h" | ||
| # pragma message "Autocorrect is using multibank." | ||
| # define AML ((AUTOCORRECT_MAX_LENGTH > AUTOCORRECT_MAX_LENGTH_ALT) ? AUTOCORRECT_MAX_LENGTH : AUTOCORRECT_MAX_LENGTH_ALT) |
There was a problem hiding this comment.
For sake of readability, abbreviations in names are for the most part best avoided. Maybe call this "TYPO_BUFFER_SIZE" to be more descriptive.
| # define AML ((AUTOCORRECT_MAX_LENGTH > AUTOCORRECT_MAX_LENGTH_ALT) ? AUTOCORRECT_MAX_LENGTH : AUTOCORRECT_MAX_LENGTH_ALT) | |
| # define TYPO_BUFFER_SIZE ((AUTOCORRECT_MAX_LENGTH > AUTOCORRECT_MAX_LENGTH_ALT) ? AUTOCORRECT_MAX_LENGTH : AUTOCORRECT_MAX_LENGTH_ALT) |
| // Check for typo in buffer using a trie stored in `AUTOCORRECT_DATA`. | ||
| uint16_t state = 0; | ||
| uint8_t code = pgm_read_byte(autocorrect_data + state); | ||
| uint8_t code = pgm_read_byte(AUTOCORRECT_DATA + state); |
There was a problem hiding this comment.
It's confusing that AUTOCORRECT_DATA is a macro expanding to either autocorrect_data or bank_data, yet #ifdefs are used for other parameters like AUTOCORRECT_MIN_LENGTH vs. bank_min_length.
To unify naming and simplify away the #ifdefs, how about define a set of macros above like
#ifdef AUTOCORRECT_MULTI_BANK
// Dual bank.
#define CURRENT_DATA bank_data
#define CURRENT_MIN_LENGTH bank_min_length
#define CURRENT_MAX_LENGTH bank_max_length
#define CURRENT_SIZE bank_size
#else
// Single bank.
#define CURRENT_DATA autocorrect_data
#define CURRENT_MIN_LENGTH AUTOCORRECT_MIN_LENGTH
#define CURRENT_MAX_LENGTH AUTOCORRECT_MAX_LENGTH
#define CURRENT_SIZE DICTIONARY_SIZE
#endif This way the bank_ variables are used when the option is enabled or the constants if not, and the "current" prefix makes clear that these parameters can change.
There was a problem hiding this comment.
Makes sense! I implemented this alongside the struct packing change, which cleaned things up nicely.
| static const uint8_t *bank_data = autocorrect_data; | ||
| static uint16_t bank_min_length = AUTOCORRECT_MIN_LENGTH; | ||
| static uint16_t bank_max_length = AUTOCORRECT_MAX_LENGTH; | ||
| static uint16_t bank_size = DICTIONARY_SIZE; |
There was a problem hiding this comment.
Make a "bank_params_t" struct for bank parameters. Then the bank-related definitions can be corralled like:
typedef struct {
const uint8_t* data;
uint16_t min_length;
uint16_t max_length;
uint16_t size;
} bank_params_t;
#define PRIMARY_BANK (bank_params_t){ \
.data = autocorrect_data, \
.min_length = AUTOCORRECT_MIN_LENGTH, \
.max_length = AUTOCORRECT_MAX_LENGTH, \
.size = DICTIONARY_SIZE, \
}
#define ALT_BANK (bank_params_t){ \
.data = autocorrect_data_alt, \
.min_length = AUTOCORRECT_MIN_LENGTH_ALT, \
.max_length = AUTOCORRECT_MAX_LENGTH_ALT, \
.size = DICTIONARY_SIZE_ALT, \
}
static bank_params_t bank = PRIMARY_BANK;
void autocorrect_init_bank(void) {
typo_buffer_size = 0;
bank = keymap_config.autocorrect_bank ? ALT_BANK : PRIMARY_BANK;
}
docs/feature_autocorrect.md
Outdated
| | `autocorrect_disable()` | Turns Autocorrect off. | | ||
| | `autocorrect_toggle()` | Toggles Autocorrect. | | ||
| | `autocorrect_is_enabled()` | Returns true if Autocorrect is currently on. | | ||
| | `autocorrect_bank_toggle()`| Toggles and initializes Autocorrect dictionary (if multiple present) | |
There was a problem hiding this comment.
Dictionaries are constant data, they do not need to be initialized. The only initialization made is that the typo buffer is cleared, which is probably too low level to be worth mentioning. I think the description written for AC_BANK is clear and could be reused here:
| | `autocorrect_bank_toggle()`| Toggles and initializes Autocorrect dictionary (if multiple present) | | |
| | `autocorrect_bank_toggle()`| Toggles the dictionary in use by the Autocorrect feature (if an alternate is present) | |
docs/feature_autocorrect.md
Outdated
| | `autocorrect_toggle()` | Toggles Autocorrect. | | ||
| | `autocorrect_is_enabled()` | Returns true if Autocorrect is currently on. | | ||
| | `autocorrect_bank_toggle()`| Toggles and initializes Autocorrect dictionary (if multiple present) | | ||
| | `autocorrect_init_bank()` | Initializes current dictionary according so selected bank (if multiple present) | |
There was a problem hiding this comment.
Is autocorrect_init_bank() useful to users? AIUI, the point of this function is to set the EEPROM bank selection in suspend_wakeup_init_quantum(), which is pretty specific. I suggest omitting this function from the documentation.
There was a problem hiding this comment.
fair point, it's more of an implementation detail; I removed the mention
9fcba5e to
88d04fc
Compare
|
Thanks @drashna and @getreuer for the excellent feedback! Sorry for letting this sit for so long, work kept me busy. I've made the requested changes and retested the feature, I haven't seen any regressions. Your suggestion for cleaning up the swapping logic using a struct worked out a lot nicer than my previous approach. |
|
I've also rebased on the latest develop, so this should merge without issue |
|
FWIW: i openned a PR against your changes to make them more flexible, which you apparently missed (:
|
|
@elpekenin Ah! you are right; I completely missed it, sorry about that. I just gave it a look over, and it's a reasonable generalization to make. I like the struct corralling suggested by @getreuer, so I'll merge you changes into my fork and add back the struct changes. the result should be the best of both worlds. I've changed the PR to draft in the meantime. Thanks for pointing that out! I see your changes take 3 EEPROM bits for saving the current dict, which I think is probably fine, but I recall the current count being close to the next byte over so any thoughts on that would be appreciated |
88d04fc to
b1a83d2
Compare
[Enhancement] *Multi*dict
|
I barely tested the changes, so please do! |
| @cli.argument('-km', '--keymap', completer=keymap_completer, help='The keymap to build a firmware for. Ignored when a configurator export is supplied.') | ||
| @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') | ||
| @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") | ||
| @cli.argument('-a', '--alternate', arg_only=True, action='store_true', help="Create an alternate dictionary file") |
There was a problem hiding this comment.
Not needed anymore
| @cli.argument('-a', '--alternate', arg_only=True, action='store_true', help="Create an alternate dictionary file") |
| file_name = 'autocorrect_data_alt.h' if cli.args.alternate else 'autocorrect_data.h' | ||
| defines_suffix = '_ALT' if cli.args.alternate else '' | ||
| static_suffix = '_alt' if cli.args.alternate else '' |
There was a problem hiding this comment.
Not needed either, we have a single file and single data structure now
| data = [] | ||
| maxs = [] | ||
| mins = [] | ||
| sizes = [] |
There was a problem hiding this comment.
Could make this a one liner instead:
| data = [] | |
| maxs = [] | |
| mins = [] | |
| sizes = [] | |
| data, maxs, mins, sizes = [], [], [], [] |
| autocorrect_data_h_lines.append(f'#define TYPO_BUFFER_SIZE {max(maxs)}') | ||
| autocorrect_data_h_lines.append('') | ||
| autocorrect_data_h_lines.append('static const uint8_t autocorrect_data[DICTIONARY_SIZE] PROGMEM = {') | ||
| autocorrect_data_h_lines.append(f'static const uint8_t autocorrect_data{static_suffix}[DICTIONARY_SIZE{defines_suffix}] PROGMEM = {{') |
There was a problem hiding this comment.
Single structure
| autocorrect_data_h_lines.append(f'static const uint8_t autocorrect_data{static_suffix}[DICTIONARY_SIZE{defines_suffix}] PROGMEM = {{') | |
| autocorrect_data_h_lines.append(f'static const uint8_t autocorrect_data[DICTIONARY_SIZE] PROGMEM = {{') |
| bool oneshot_enable : 1; | ||
| bool swap_escape_capslock : 1; | ||
| bool autocorrect_enable : 1; | ||
| uint8_t autocorrect_curr_dict : 3; |
There was a problem hiding this comment.
This (and respective check on the Py code-gen) should perhaps be lowered to 2 or even 1 bit, to not exhaust all available space in current EEPROM footprint.
| #if __has_include("autocorrect_data_alt.h") | ||
| # define AUTOCORRECT_MULTI_BANK | ||
| #endif |
There was a problem hiding this comment.
| #if __has_include("autocorrect_data_alt.h") | |
| # define AUTOCORRECT_MULTI_BANK | |
| #endif |
| #ifdef AUTOCORRECT_ENABLE | ||
| // refresh autocorrect bank | ||
| autocorrect_init_dict(); | ||
|
|
Description
Allows for users to define two banks of autocorrect rules and switch between them dynamically. Bank selection is persisted in EEPROM, and persisted selection is loaded on wake of keyboard. Code for bank switching is not compiled if no alternate bank is found, thus eliminating unneeded memory footprint. This PR adds a new keycode (which I hope I've added correctly!) and extends the QMK python CLI to allow for easy generation of the alternate dictionary files. I've updated the documentation, please feel free to ask questions and make suggestions if anything is unclear.
Any pointers with regards to code formatting and peprocessor directives are appreciated, although I've tried to follow guidelines to the best of my ability.
Thanks!
-Sean
Types of Changes
Checklist