Skip to content

Add a personal dictionary with shortcuts - #1384

Open
Gareth-Rouse wants to merge 3 commits into
Julow:masterfrom
Gareth-Rouse:personal-dictionary
Open

Gareth-Rouse wants to merge 3 commits into
Julow:masterfrom
Gareth-Rouse:personal-dictionary

Conversation

@Gareth-Rouse

Copy link
Copy Markdown

Adds a user-maintained personal dictionary: words and abbreviations entered in settings appear in the suggestion bar, independent of the compiled dictionaries.

Features

  • New Personal dictionary settings screen (under Suggestions) using ListGroupPreference; entries are stored as JSON (plain strings, or {word, shortcut} objects when a shortcut is attached — old plain-string lists keep loading).
  • Words are suggested on a case-insensitive prefix match; stored casing is preserved and follows the capitalization of the typed word, matching the behavior of compiled-dictionary suggestions.
  • Shortcuts: typing a shortcut exactly expands to the full word/text (e.g. aa → an email address). Expansions rank first and are returned verbatim.
  • Matching uses the same substitution table as the compiled dictionaries (ComposeKey.transform_char(ComposeKeyData.substitutions, …)), normalized once at load time, so typing cafe matches a stored café and vice-versa.
  • Suggestion slots: shortcut expansions take the first slots, then the compiled dictionary, then personal word matches fill whatever slots remain — personal words can never hide dictionary results entirely, and an empty dictionary result never wastes a slot.
  • The entry dialog rejects shortcuts that can never fire (shorter than the 2-character suggestion gate, or containing non-word characters per CurrentlyTypedWord.is_word_char).
  • Personal suggestions work with no dictionary installed.

Also in this PR

  • ListGroupPreference.StringSerializer.load_item now throws JSONException instead of ClassCastException when an item isn't a string, so a future format change degrades to an empty list instead of crashing Config.refresh on downgrade/upgrade.
  • Unit tests for PersonalDictionary (matching, ranking, capitalization, substitutions, dedup, truncation): 7 tests.

Tested on-device (debug build, installed as a separate app id).

Gareth-Rouse added 3 commits August 9, 2026 17:05
Words added in Settings > Suggestions > Personal dictionary are
suggested when a prefix of them is typed. Stored as a JSON string list
in preferences, mirroring custom extra keys. Personal matches rank
before dictionary matches and keep their stored casing; suggestions now
also work when no compiled dictionary is installed.
An entry can have a shortcut attached, e.g. "aa" for an email address.
Typing the shortcut exactly (case-insensitive) suggests the word,
ranked before other matches and inserted verbatim. Entries without a
shortcut are stored as before (plain strings), so existing preferences
keep loading.

Word-match capitalization moves into PersonalDictionary so shortcut
expansions are never capitalized. Also includes: personal words leave
one suggestion slot for the compiled dictionary, and a max<=0 guard.
- Match personal entries against the raw typed word with an explicit
  capitalize flag; substitutions lower-case A-Z, which made the
  capitalization path dead code and broke matching of accented words.
  Entries are now normalized once at load with the same substitution
  table used for typed text, so cafe matches café in both directions.
- Fill suggestion slots left unused by the compiled dictionary with
  personal word matches instead of reserving a slot that may go empty.
- Reject shortcuts that can never fire in the entry dialog.
- Make StringSerializer tolerant of format changes (JSONObject items
  now throw JSONException, handled, instead of crashing Config.refresh).
- Label the word/shortcut dialog fields.

@Julow Julow left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I have to postpone reviewing your PR a bit more as I'm preparing for a new release and don't have enough time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants