Merge pull request #2132 from profanity-im/feat/spellcheck
Add spellchecking
This commit is contained in:
13
meson.build
13
meson.build
@@ -160,6 +160,7 @@ gdk_pixbuf_dep = disabler()
|
||||
omemo_dep = disabler()
|
||||
gcrypt_dep = disabler()
|
||||
qrencode_dep = disabler()
|
||||
enchant_dep = disabler()
|
||||
|
||||
# Dependencies for functional tests
|
||||
stabber_dep = cc.find_library('stabber', required: false)
|
||||
@@ -269,6 +270,12 @@ if get_option('omemo-qrcode').enabled()
|
||||
conf_data.set('HAVE_QRENCODE', 1)
|
||||
endif
|
||||
|
||||
# Spellcheck support
|
||||
if get_option('spellcheck').enabled()
|
||||
enchant_dep = dependency('enchant-2', required: true)
|
||||
conf_data.set('HAVE_SPELLCHECK', 1)
|
||||
endif
|
||||
|
||||
# Set installation paths
|
||||
themes_path = get_option('themes_path')
|
||||
if themes_path == ''
|
||||
@@ -355,6 +362,10 @@ if qrencode_dep.found()
|
||||
profanity_deps += qrencode_dep
|
||||
endif
|
||||
|
||||
if enchant_dep.found()
|
||||
profanity_deps += enchant_dep
|
||||
endif
|
||||
|
||||
# Include directories
|
||||
inc = include_directories('.', 'src')
|
||||
|
||||
@@ -419,6 +430,7 @@ core_sources = files(
|
||||
'src/tools/autocomplete.c',
|
||||
'src/tools/clipboard.c',
|
||||
'src/tools/editor.c',
|
||||
'src/tools/spellcheck.c',
|
||||
'src/config/files.c',
|
||||
'src/config/conflists.c',
|
||||
'src/config/accounts.c',
|
||||
@@ -584,6 +596,7 @@ if get_option('tests')
|
||||
'src/tools/autocomplete.c',
|
||||
'src/tools/clipboard.c',
|
||||
'src/tools/editor.c',
|
||||
'src/tools/spellcheck.c',
|
||||
'src/tools/bookmark_ignore.c',
|
||||
'src/config/account.c',
|
||||
'src/config/files.c',
|
||||
|
||||
@@ -66,6 +66,12 @@ option('omemo-qrcode',
|
||||
description: 'Enable ability to display OMEMO QR code'
|
||||
)
|
||||
|
||||
option('spellcheck',
|
||||
type: 'feature',
|
||||
value: 'disabled',
|
||||
description: 'Enable spellchecking support'
|
||||
)
|
||||
|
||||
# Other:
|
||||
option('python_framework',
|
||||
type: 'string',
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
static char* _sub_autocomplete(ProfWin* window, const char* const input, gboolean previous);
|
||||
static char* _notify_autocomplete(ProfWin* window, const char* const input, gboolean previous);
|
||||
static char* _theme_autocomplete(ProfWin* window, const char* const input, gboolean previous);
|
||||
static char* _spellcheck_autocomplete(ProfWin* window, const char* const input, gboolean previous);
|
||||
static char* _autoaway_autocomplete(ProfWin* window, const char* const input, gboolean previous);
|
||||
static char* _autoconnect_autocomplete(ProfWin* window, const char* const input, gboolean previous);
|
||||
static char* _account_autocomplete(ProfWin* window, const char* const input, gboolean previous);
|
||||
@@ -138,6 +139,7 @@ static Autocomplete autoconnect_ac;
|
||||
static Autocomplete wintitle_ac;
|
||||
static Autocomplete theme_ac;
|
||||
static Autocomplete theme_load_ac;
|
||||
static Autocomplete spellcheck_ac;
|
||||
static Autocomplete account_ac;
|
||||
static Autocomplete account_set_ac;
|
||||
static Autocomplete account_clear_ac;
|
||||
@@ -298,6 +300,7 @@ static Autocomplete* all_acs[] = {
|
||||
&autoconnect_ac,
|
||||
&wintitle_ac,
|
||||
&theme_ac,
|
||||
&spellcheck_ac,
|
||||
&account_ac,
|
||||
&account_set_ac,
|
||||
&account_clear_ac,
|
||||
@@ -563,6 +566,11 @@ cmd_ac_init(void)
|
||||
autocomplete_add(theme_ac, "colours");
|
||||
autocomplete_add(theme_ac, "properties");
|
||||
|
||||
autocomplete_add(spellcheck_ac, "on");
|
||||
autocomplete_add(spellcheck_ac, "off");
|
||||
autocomplete_add(spellcheck_ac, "list");
|
||||
autocomplete_add(spellcheck_ac, "lang");
|
||||
|
||||
autocomplete_add(disco_ac, "info");
|
||||
autocomplete_add(disco_ac, "items");
|
||||
|
||||
@@ -1748,6 +1756,16 @@ cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean
|
||||
return autocomplete_param_with_ac(input, startstr, filepath_ac, TRUE, previous);
|
||||
}
|
||||
|
||||
static char*
|
||||
_spellcheck_autocomplete(ProfWin* window, const char* const input, gboolean previous)
|
||||
{
|
||||
char* result = NULL;
|
||||
|
||||
result = autocomplete_param_with_ac(input, "/spellcheck", spellcheck_ac, TRUE, previous);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static char*
|
||||
_cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previous)
|
||||
{
|
||||
@@ -1767,6 +1785,11 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
|
||||
}
|
||||
}
|
||||
|
||||
result = _spellcheck_autocomplete(window, input, previous);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// autocomplete nickname in chat rooms
|
||||
if (window->type == WIN_MUC) {
|
||||
ProfMucWin* mucwin = (ProfMucWin*)window;
|
||||
|
||||
@@ -1451,6 +1451,23 @@ static const struct cmd_t command_defs[] = {
|
||||
{ "on|off", "Enable or disable splash logo." })
|
||||
},
|
||||
|
||||
{ CMD_PREAMBLE("/spellcheck",
|
||||
parse_args, 1, 2, &cons_spellcheck_setting)
|
||||
CMD_MAINFUNC(cmd_spellcheck)
|
||||
CMD_TAGS(
|
||||
CMD_TAG_UI)
|
||||
CMD_SYN(
|
||||
"/spellcheck on|off",
|
||||
"/spellcheck list",
|
||||
"/spellcheck lang <locale>")
|
||||
CMD_DESC(
|
||||
"Enable or disable spellchecking, or set the language.")
|
||||
CMD_ARGS(
|
||||
{ "on|off", "Enable or disable spellchecking." },
|
||||
{ "list", "List available dictionaries recognized by Enchant." },
|
||||
{ "lang <locale>", "Set the spellcheck language (en_US)." })
|
||||
},
|
||||
|
||||
{ CMD_PREAMBLE("/autoconnect",
|
||||
parse_args, 1, 2, &cons_autoconnect_setting)
|
||||
CMD_MAINFUNC(cmd_autoconnect)
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include "tools/plugin_download.h"
|
||||
#include "tools/bookmark_ignore.h"
|
||||
#include "tools/editor.h"
|
||||
#include "tools/spellcheck.h"
|
||||
#include "plugins/plugins.h"
|
||||
#include "ui/inputwin.h"
|
||||
#include "ui/ui.h"
|
||||
@@ -6560,6 +6561,55 @@ cmd_splash(ProfWin* window, const char* const command, gchar** args)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
cmd_spellcheck(ProfWin* window, const char* const command, gchar** args)
|
||||
{
|
||||
#ifdef HAVE_SPELLCHECK
|
||||
if (g_strcmp0(args[0], "on") == 0) {
|
||||
prefs_set_boolean(PREF_SPELLCHECK_ENABLE, TRUE);
|
||||
cons_show("Spellcheck enabled.");
|
||||
} else if (g_strcmp0(args[0], "off") == 0) {
|
||||
prefs_set_boolean(PREF_SPELLCHECK_ENABLE, FALSE);
|
||||
cons_show("Spellcheck disabled.");
|
||||
} else if (g_strcmp0(args[0], "list") == 0) {
|
||||
GList* langs = spellcheck_get_available_langs();
|
||||
if (langs == NULL) {
|
||||
cons_show("No dictionaries found. Install Enchant-compatible dictionaries (hunspell/aspell).");
|
||||
} else {
|
||||
GString* lang_str = g_string_new("");
|
||||
GList* curr = langs;
|
||||
while (curr) {
|
||||
g_string_append(lang_str, (char*)curr->data);
|
||||
if (curr->next) {
|
||||
g_string_append(lang_str, ", ");
|
||||
}
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
cons_show("Available spellcheck dictionaries: %s", lang_str->str);
|
||||
g_string_free(lang_str, TRUE);
|
||||
g_list_free_full(langs, g_free);
|
||||
}
|
||||
} else if (g_strcmp0(args[0], "lang") == 0) {
|
||||
if (args[1] == NULL) {
|
||||
cons_bad_cmd_usage(command);
|
||||
} else {
|
||||
if (spellcheck_set_lang(args[1])) {
|
||||
prefs_set_string(PREF_SPELLCHECK_LANG, args[1]);
|
||||
cons_show("Spellcheck language set to: %s", args[1]);
|
||||
} else {
|
||||
cons_show("Failed to set spellcheck language to: %s. Is the dictionary installed?", args[1]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cons_bad_cmd_usage(command);
|
||||
}
|
||||
#else
|
||||
cons_show("Profanity was built without spellcheck support.");
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
cmd_autoconnect(ProfWin* window, const char* const command, gchar** args)
|
||||
{
|
||||
|
||||
@@ -103,6 +103,7 @@ gboolean cmd_bookmark_ignore(ProfWin* window, const char* const command, gchar**
|
||||
gboolean cmd_roster(ProfWin* window, const char* const command, gchar** args);
|
||||
gboolean cmd_software(ProfWin* window, const char* const command, gchar** args);
|
||||
gboolean cmd_splash(ProfWin* window, const char* const command, gchar** args);
|
||||
gboolean cmd_spellcheck(ProfWin* window, const char* const command, gchar** args);
|
||||
gboolean cmd_states(ProfWin* window, const char* const command, gchar** args);
|
||||
gboolean cmd_status_get(ProfWin* window, const char* const command, gchar** args);
|
||||
gboolean cmd_status_set(ProfWin* window, const char* const command, gchar** args);
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#define PREF_GROUP_MUC "muc"
|
||||
#define PREF_GROUP_PLUGINS "plugins"
|
||||
#define PREF_GROUP_EXECUTABLES "executables"
|
||||
#define PREF_GROUP_SPELLCHECK "spellcheck"
|
||||
|
||||
#define INPBLOCK_DEFAULT 1000
|
||||
|
||||
@@ -1909,6 +1910,9 @@ _get_group(preference_t pref)
|
||||
return PREF_GROUP_OMEMO;
|
||||
case PREF_OX_LOG:
|
||||
return PREF_GROUP_OX;
|
||||
case PREF_SPELLCHECK_ENABLE:
|
||||
case PREF_SPELLCHECK_LANG:
|
||||
return PREF_GROUP_SPELLCHECK;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@@ -2196,6 +2200,10 @@ _get_key(preference_t pref)
|
||||
return "strophe.sm.enabled";
|
||||
case PREF_STROPHE_SM_RESEND:
|
||||
return "strophe.sm.resend";
|
||||
case PREF_SPELLCHECK_ENABLE:
|
||||
return "enabled";
|
||||
case PREF_SPELLCHECK_LANG:
|
||||
return "lang";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@@ -2249,6 +2257,7 @@ _get_default_boolean(preference_t pref)
|
||||
case PREF_STROPHE_SM_ENABLED:
|
||||
case PREF_STROPHE_SM_RESEND:
|
||||
return TRUE;
|
||||
case PREF_SPELLCHECK_ENABLE:
|
||||
case PREF_PGP_PUBKEY_AUTOIMPORT:
|
||||
default:
|
||||
return FALSE;
|
||||
@@ -2356,6 +2365,8 @@ _get_default_string(preference_t pref)
|
||||
return "0";
|
||||
case PREF_DBLOG:
|
||||
return "on";
|
||||
case PREF_SPELLCHECK_LANG:
|
||||
return "en_US";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -161,6 +161,8 @@ typedef enum {
|
||||
PREF_STROPHE_SM_RESEND,
|
||||
PREF_VCARD_PHOTO_CMD,
|
||||
PREF_STATUSBAR_TABMODE,
|
||||
PREF_SPELLCHECK_ENABLE,
|
||||
PREF_SPELLCHECK_LANG,
|
||||
} preference_t;
|
||||
|
||||
typedef struct prof_alias_t
|
||||
|
||||
@@ -90,6 +90,7 @@ theme_init(const char* const theme_name)
|
||||
g_hash_table_insert(defaults, strdup("mention"), strdup("yellow"));
|
||||
g_hash_table_insert(defaults, strdup("trigger"), strdup("yellow"));
|
||||
g_hash_table_insert(defaults, strdup("input.text"), strdup("default"));
|
||||
g_hash_table_insert(defaults, strdup("input.misspelled"), strdup("red"));
|
||||
g_hash_table_insert(defaults, strdup("main.time"), strdup("default"));
|
||||
g_hash_table_insert(defaults, strdup("titlebar.text"), strdup("white"));
|
||||
g_hash_table_insert(defaults, strdup("titlebar.brackets"), strdup("cyan"));
|
||||
@@ -713,6 +714,9 @@ theme_attrs(theme_item_t attrs)
|
||||
case THEME_INPUT_TEXT:
|
||||
_theme_prep_fgnd("input.text", lookup_str, &bold);
|
||||
break;
|
||||
case THEME_INPUT_MISSPELLED:
|
||||
_theme_prep_fgnd("input.misspelled", lookup_str, &bold);
|
||||
break;
|
||||
case THEME_TIME:
|
||||
_theme_prep_fgnd("main.time", lookup_str, &bold);
|
||||
break;
|
||||
|
||||
@@ -27,6 +27,7 @@ typedef enum {
|
||||
THEME_MENTION,
|
||||
THEME_TRIGGER,
|
||||
THEME_INPUT_TEXT,
|
||||
THEME_INPUT_MISSPELLED,
|
||||
THEME_TIME,
|
||||
THEME_TITLE_TEXT,
|
||||
THEME_TITLE_BRACKET,
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "config/accounts.h"
|
||||
#include "config/preferences.h"
|
||||
#include "config/theme.h"
|
||||
#include "tools/spellcheck.h"
|
||||
#include "config/tlscerts.h"
|
||||
#include "config/scripts.h"
|
||||
#include "command/cmd_defs.h"
|
||||
@@ -234,6 +235,7 @@ _init(char* log_level, char* config_file, char* log_file, char* theme_name)
|
||||
#ifdef HAVE_OMEMO
|
||||
omemo_init();
|
||||
#endif
|
||||
spellcheck_init();
|
||||
atexit(_shutdown);
|
||||
plugins_init();
|
||||
#ifdef HAVE_GTK
|
||||
|
||||
132
src/tools/spellcheck.c
Normal file
132
src/tools/spellcheck.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* spellcheck.c
|
||||
* vim: expandtab:ts=4:sts=4:sw=4
|
||||
*
|
||||
* Copyright (C) 2026 Michael Vetter <jubalh@iodoru.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_SPELLCHECK
|
||||
|
||||
#include <enchant.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "tools/spellcheck.h"
|
||||
#include "config/preferences.h"
|
||||
#include "log.h"
|
||||
#include "common.h"
|
||||
|
||||
static EnchantBroker* broker = NULL;
|
||||
static EnchantDict* dict = NULL;
|
||||
static char* current_lang = NULL;
|
||||
|
||||
void
|
||||
spellcheck_init(void)
|
||||
{
|
||||
if (broker) {
|
||||
return;
|
||||
}
|
||||
|
||||
broker = enchant_broker_init();
|
||||
if (!broker) {
|
||||
log_error("Failed to initialize Enchant broker");
|
||||
return;
|
||||
}
|
||||
|
||||
prof_add_shutdown_routine(spellcheck_deinit);
|
||||
|
||||
char* lang = prefs_get_string(PREF_SPELLCHECK_LANG);
|
||||
spellcheck_set_lang(lang);
|
||||
g_free(lang);
|
||||
}
|
||||
|
||||
void
|
||||
spellcheck_deinit(void)
|
||||
{
|
||||
if (dict) {
|
||||
enchant_broker_free_dict(broker, dict);
|
||||
dict = NULL;
|
||||
}
|
||||
if (broker) {
|
||||
enchant_broker_free(broker);
|
||||
broker = NULL;
|
||||
}
|
||||
g_free(current_lang);
|
||||
current_lang = NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
spellcheck_set_lang(const char* lang)
|
||||
{
|
||||
if (!broker || !lang) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (current_lang && strcmp(current_lang, lang) == 0 && dict) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
EnchantDict* new_dict = enchant_broker_request_dict(broker, lang);
|
||||
if (!new_dict) {
|
||||
log_error("Failed to request Enchant dictionary for language: %s", lang);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (dict) {
|
||||
enchant_broker_free_dict(broker, dict);
|
||||
}
|
||||
|
||||
dict = new_dict;
|
||||
g_free(current_lang);
|
||||
current_lang = g_strdup(lang);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const char*
|
||||
spellcheck_get_lang(void)
|
||||
{
|
||||
return current_lang;
|
||||
}
|
||||
|
||||
static void
|
||||
_list_dicts_cb(const char* const lang_tag,
|
||||
const char* const provider_name,
|
||||
const char* const provider_desc,
|
||||
const char* const provider_file,
|
||||
void* user_data)
|
||||
{
|
||||
GList** list = (GList**)user_data;
|
||||
if (g_list_find_custom(*list, lang_tag, (GCompareFunc)g_strcmp0) == NULL) {
|
||||
*list = g_list_append(*list, g_strdup(lang_tag));
|
||||
}
|
||||
}
|
||||
|
||||
GList*
|
||||
spellcheck_get_available_langs(void)
|
||||
{
|
||||
if (!broker) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GList* list = NULL;
|
||||
enchant_broker_list_dicts(broker, _list_dicts_cb, &list);
|
||||
return g_list_sort(list, (GCompareFunc)g_strcmp0);
|
||||
}
|
||||
|
||||
gboolean
|
||||
spellcheck_is_misspelled(const char* word)
|
||||
{
|
||||
if (!dict || !word || word[0] == '\0') {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int result = enchant_dict_check(dict, word, strlen(word));
|
||||
return (result != 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
58
src/tools/spellcheck.h
Normal file
58
src/tools/spellcheck.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* spellcheck.h
|
||||
* vim: expandtab:ts=4:sts=4:sw=4
|
||||
*
|
||||
* Copyright (C) 2026 Michael Vetter <jubalh@iodoru.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
|
||||
*/
|
||||
|
||||
#ifndef TOOLS_SPELLCHECK_H
|
||||
#define TOOLS_SPELLCHECK_H
|
||||
|
||||
#include "config.h"
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef HAVE_SPELLCHECK
|
||||
|
||||
void spellcheck_init(void);
|
||||
void spellcheck_deinit(void);
|
||||
gboolean spellcheck_is_misspelled(const char* word);
|
||||
gboolean spellcheck_set_lang(const char* lang);
|
||||
const char* spellcheck_get_lang(void);
|
||||
GList* spellcheck_get_available_langs(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline void
|
||||
spellcheck_init(void)
|
||||
{
|
||||
}
|
||||
static inline void
|
||||
spellcheck_deinit(void)
|
||||
{
|
||||
}
|
||||
static inline gboolean
|
||||
spellcheck_is_misspelled(const char* word)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
static inline gboolean
|
||||
spellcheck_set_lang(const char* lang)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
static inline const char*
|
||||
spellcheck_get_lang(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline GList*
|
||||
spellcheck_get_available_langs(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -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("");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1008,6 +1008,10 @@ cons_splash_setting(void)
|
||||
{
|
||||
}
|
||||
void
|
||||
cons_spellcheck_setting(void)
|
||||
{
|
||||
}
|
||||
void
|
||||
cons_vercheck_setting(void)
|
||||
{
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user