feat: add spellcheck highlighting support

Introduce optional spellcheck highlighting in the input window using
the Enchant-2 library.

```
/spellcheck on
/spellcheck lang en_US
```

New theme color `input.misspelled`.

Fixes: https://github.com/profanity-im/profanity/issues/183
Signed-off-by: Michael Vetter <jubalh@iodoru.org>
This commit is contained in:
Michael Vetter
2026-03-26 22:37:06 +01:00
parent 88b80c33ef
commit 4922366366
17 changed files with 335 additions and 0 deletions

View File

@@ -1270,6 +1270,21 @@ cons_splash_setting(void)
cons_show("Splash screen (/splash) : OFF");
}
void
cons_spellcheck_setting(void)
{
#ifdef HAVE_SPELLCHECK
if (prefs_get_boolean(PREF_SPELLCHECK_ENABLE)) {
auto_gchar gchar* lang = prefs_get_string(PREF_SPELLCHECK_LANG);
cons_show("Spellcheck (/spellcheck) : ON (%s)", lang);
} else {
cons_show("Spellcheck (/spellcheck) : OFF");
}
#else
cons_show("Spellcheck (/spellcheck) : built without spellcheck support");
#endif
}
void
cons_occupants_setting(void)
{
@@ -1589,6 +1604,7 @@ cons_show_ui_prefs(void)
cons_beep_setting();
cons_flash_setting();
cons_splash_setting();
cons_spellcheck_setting();
cons_winpos_setting();
cons_wrap_setting();
cons_time_setting();
@@ -2572,6 +2588,7 @@ cons_theme_properties(void)
_cons_theme_prop(console, THEME_RECEIPT_SENT, "receipt.sent");
_cons_theme_prop(console, THEME_INPUT_TEXT, "input.text");
_cons_theme_prop(console, THEME_INPUT_MISSPELLED, "input.misspelled");
cons_show("");
}

View File

@@ -50,6 +50,7 @@
#include "xmpp/roster_list.h"
#include "xmpp/chat_state.h"
#include "tools/editor.h"
#include "tools/spellcheck.h"
static WINDOW* inp_win;
static int pad_start = 0;
@@ -327,6 +328,8 @@ _inp_write(char* line, int offset)
getyx(inp_win, y, x);
col += x;
gboolean do_spell = prefs_get_boolean(PREF_SPELLCHECK_ENABLE) && (line[0] != '/');
for (size_t i = 0; line[i] != '\0'; i++) {
char* c = &line[i];
char retc[PROF_MB_CUR_MAX] = { 0 };
@@ -348,6 +351,47 @@ _inp_write(char* line, int offset)
i += ch_len - 1;
}
if (do_spell) {
gunichar uc = g_utf8_get_char(c);
if (g_unichar_isalnum(uc) || uc == '\'') {
// start of a word
size_t start = i - (ch_len - 1);
size_t end = start + ch_len;
while (line[end] != '\0') {
size_t next_ch_len = mbrlen(&line[end], MB_CUR_MAX, NULL);
if (next_ch_len == (size_t)-2 || next_ch_len == (size_t)-1)
break;
gunichar next_uc = g_utf8_get_char(&line[end]);
if (!g_unichar_isalnum(next_uc) && next_uc != '\'')
break;
end += next_ch_len;
}
char* word = g_strndup(&line[start], end - start);
gboolean misspelled = spellcheck_is_misspelled(word);
g_free(word);
if (misspelled) {
wattron(inp_win, theme_attrs(THEME_INPUT_MISSPELLED));
}
// add the word
size_t word_pos = start;
while (word_pos < end) {
size_t cur_ch_len = mbrlen(&line[word_pos], MB_CUR_MAX, NULL);
waddnstr(inp_win, &line[word_pos], cur_ch_len);
word_pos += cur_ch_len;
}
if (misspelled) {
wattroff(inp_win, theme_attrs(THEME_INPUT_MISSPELLED));
}
i = end - 1;
continue;
}
}
waddnstr(inp_win, c, ch_len);
}

View File

@@ -284,6 +284,7 @@ void cons_console_setting(void);
void cons_flash_setting(void);
void cons_tray_setting(void);
void cons_splash_setting(void);
void cons_spellcheck_setting(void);
void cons_titlebar_setting(void);
void cons_vercheck_setting(void);
void cons_occupants_setting(void);