-
-
Notifications
You must be signed in to change notification settings - Fork 38.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dualbank Autocorrect #22788
base: develop
Are you sure you want to change the base?
Dualbank Autocorrect #22788
Conversation
@@ -19,8 +19,24 @@ | |||
# include "autocorrect_data_default.h" | |||
#endif | |||
|
|||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"dual bank" seems more accurate, than "multibank".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: The sentence is missing a period .
at the end.
@@ -263,8 +264,12 @@ def generate_autocorrect_data(cli): | |||
current_keyboard = cli.args.keyboard or cli.config.user.keyboard or cli.config.generate_autocorrect_data.keyboard | |||
current_keymap = cli.args.keymap or cli.config.user.keymap or cli.config.generate_autocorrect_data.keymap | |||
|
|||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, good point
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
#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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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) |
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's much cleaner, thanks!
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A quick sanity check
@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.') | ||
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed either, we have a single file and single data structure now
data = [] | ||
maxs = [] | ||
mins = [] | ||
sizes = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could make this a one liner instead:
data = [] | |
maxs = [] | |
mins = [] | |
sizes = [] | |
data, maxs, mins, sizes = [], [], [], [] |
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 = {{') |
@@ -44,6 +44,7 @@ typedef union { | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#if __has_include("autocorrect_data_alt.h") | |
# define AUTOCORRECT_MULTI_BANK | |
#endif |
#ifdef AUTOCORRECT_ENABLE | ||
// refresh autocorrect bank | ||
autocorrect_init_dict(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#endif |
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