diff options
Diffstat (limited to 'src/fe-common/core')
-rw-r--r-- | src/fe-common/core/chat-completion.c | 57 | ||||
-rw-r--r-- | src/fe-common/core/completion.c | 18 | ||||
-rw-r--r-- | src/fe-common/core/fe-common-core.c | 51 | ||||
-rw-r--r-- | src/fe-common/core/fe-core-commands.c | 2 | ||||
-rw-r--r-- | src/fe-common/core/fe-exec.c | 2 | ||||
-rw-r--r-- | src/fe-common/core/fe-windows.h | 8 | ||||
-rw-r--r-- | src/fe-common/core/formats.c | 27 | ||||
-rw-r--r-- | src/fe-common/core/keyboard.c | 54 | ||||
-rw-r--r-- | src/fe-common/core/themes.c | 68 | ||||
-rw-r--r-- | src/fe-common/core/window-commands.c | 7 | ||||
-rw-r--r-- | src/fe-common/core/window-items.c | 2 |
11 files changed, 230 insertions, 66 deletions
diff --git a/src/fe-common/core/chat-completion.c b/src/fe-common/core/chat-completion.c index 97cd0565..d610008f 100644 --- a/src/fe-common/core/chat-completion.c +++ b/src/fe-common/core/chat-completion.c @@ -173,6 +173,7 @@ static void sig_message_public(SERVER_REC *server, const char *msg, { CHANNEL_REC *channel; int own; + g_return_if_fail(nick != NULL); channel = channel_find(server, target); if (channel != NULL) { @@ -185,6 +186,7 @@ static void sig_message_join(SERVER_REC *server, const char *channel, const char *nick, const char *address) { CHANNEL_REC *chanrec; + g_return_if_fail(nick != NULL); chanrec = channel_find(server, channel); if (chanrec != NULL) @@ -639,6 +641,59 @@ static void complete_window_nicks(GList **list, WINDOW_REC *window, } } +/* Checks if a line is only nicks from autocompletion. + This lets us insert colons only at the beginning of a list + of nicks */ +static int only_nicks(const char *linestart) +{ + int i = 1; + char prev; + + // at the beginning of the line + if (*linestart == '\0') { + return TRUE; + } + + /* completion_char being a whole string introduces loads of edge cases + and can't be handled generally. Skip this case; we handled the + "beginning of line" case already */ + if (completion_char[1] != '\0') + return FALSE; + + /* This would make the completion char get inserted everywhere otherwise */ + if (*completion_char == ' ') + return FALSE; + + /* First ensure that the line is of the format "foo: bar: baz" + we check this by ensuring each space is preceded by a colon or + another space */ + while (linestart[i] != '\0') { + if (linestart[i] == ' ') { + prev = linestart[i - 1]; + if (prev != *completion_char && prev != ' ') + return FALSE; + } + i += 1; + } + + /* There's an edge case here, if we're completing something + like `foo: bar ba<tab>`, then the `linestart` line will end + at "bar", and we'll miss the space. Ensure that the end + of the line is a colon followed by an optional series of spaces */ + i -= 1; + while (i >= 0) { + if (linestart[i] == ' ') { + i--; + continue; + } else if (linestart[i] == *completion_char) { + return TRUE; + } else { + break; + } + } + return FALSE; +} + static void sig_complete_word(GList **list, WINDOW_REC *window, const char *word, const char *linestart, int *want_space) @@ -691,7 +746,7 @@ static void sig_complete_word(GList **list, WINDOW_REC *window, } else if (channel != NULL) { /* nick completion .. we could also be completing a nick after /MSG from nicks in channel */ - const char *suffix = *linestart != '\0' ? NULL : completion_char; + const char *suffix = only_nicks(linestart) ? completion_char : NULL; complete_window_nicks(list, window, word, suffix); } else if (window->level & MSGLEVEL_MSGS) { /* msgs window, complete /MSG nicks */ diff --git a/src/fe-common/core/completion.c b/src/fe-common/core/completion.c index e78fe7d5..fd452e5c 100644 --- a/src/fe-common/core/completion.c +++ b/src/fe-common/core/completion.c @@ -187,12 +187,18 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i char *old; old = linestart; - linestart = *linestart == '\0' ? - g_strdup(word) : - g_strdup_printf("%s%c%s", - /* do not accidentally duplicate the word separator */ - line == wordstart - 1 ? "" : linestart, - old_wordstart[-1], word); + /* we want to move word into linestart */ + if (*linestart == '\0') { + linestart = g_strdup(word); + } else { + GString *str = g_string_new(linestart); + if (old_wordstart[-1] != str->str[str->len - 1]) { + /* do not accidentally duplicate the word separator */ + g_string_append_c(str, old_wordstart[-1]); + } + g_string_append(str, word); + linestart = g_string_free(str, FALSE); + } g_free(old); g_free(word); diff --git a/src/fe-common/core/fe-common-core.c b/src/fe-common/core/fe-common-core.c index d0d36490..ef5d2113 100644 --- a/src/fe-common/core/fe-common-core.c +++ b/src/fe-common/core/fe-common-core.c @@ -470,26 +470,49 @@ void fe_common_core_finish_init(void) gboolean strarray_find_dest(char **array, const TEXT_DEST_REC *dest) { + WI_ITEM_REC *item; + int server_tag_len, channel_type, query_type; + char **tmp; + + channel_type = module_get_uniq_id_str("WINDOW ITEM TYPE", "CHANNEL"); + query_type = module_get_uniq_id_str("WINDOW ITEM TYPE", "QUERY"); + g_return_val_if_fail(array != NULL, FALSE); + g_return_val_if_fail(dest != NULL, FALSE); + g_return_val_if_fail(dest->window != NULL, FALSE); + g_return_val_if_fail(dest->target != NULL, FALSE); - if (strarray_find(array, "*") != -1) - return TRUE; + item = window_item_find_window(dest->window, dest->server, dest->target); + if (item == NULL) { + return FALSE; + } - if (strarray_find(array, dest->target) != -1) - return TRUE; + server_tag_len = dest->server_tag != NULL ? strlen(dest->server_tag) : 0; + for (tmp = array; *tmp != NULL; tmp++) { + char *str = *tmp; + if (*str == '\0') { + continue; + } - if (dest->server_tag != NULL) { - char *tagtarget = g_strdup_printf("%s/%s", dest->server_tag, "*"); - int ret = strarray_find(array, tagtarget); - g_free(tagtarget); - if (ret != -1) - return TRUE; + if (server_tag_len && + g_ascii_strncasecmp(str, dest->server_tag, server_tag_len) == 0 && + str[server_tag_len] == '/') { + str += server_tag_len + 1; + } - tagtarget = g_strdup_printf("%s/%s", dest->server_tag, dest->target); - ret = strarray_find(array, tagtarget); - g_free(tagtarget); - if (ret != -1) + if (g_strcmp0(str, "") == 0 || g_strcmp0(str, "::all") == 0) { return TRUE; + } else if (g_ascii_strcasecmp(str, dest->target) == 0) { + return TRUE; + } else if (item->type == query_type && + g_strcmp0(str, dest->target[0] == '=' ? "::dccqueries" : + "::queries") == 0) { + return TRUE; + } else if (item->type == channel_type && + g_strcmp0(str, "::channels") == 0) { + return TRUE; + } } + return FALSE; } diff --git a/src/fe-common/core/fe-core-commands.c b/src/fe-common/core/fe-core-commands.c index fb98cc25..222543d5 100644 --- a/src/fe-common/core/fe-core-commands.c +++ b/src/fe-common/core/fe-core-commands.c @@ -114,7 +114,7 @@ static void cmd_version(char *data) } } -/* SYNTAX: CAT <file> */ +/* SYNTAX: CAT <file> [<seek position>] */ static void cmd_cat(const char *data) { char *fname, *fposstr; diff --git a/src/fe-common/core/fe-exec.c b/src/fe-common/core/fe-exec.c index 36990866..c1739d39 100644 --- a/src/fe-common/core/fe-exec.c +++ b/src/fe-common/core/fe-exec.c @@ -613,7 +613,7 @@ static void sig_exec_input(PROCESS_REC *rec, const char *text) str = g_strconcat(rec->target_nick ? "-nick " : rec->target_channel ? "-channel " : "", - rec->target, " ", text, NULL); + rec->target, " ", *text == '\0' ? " " : text, NULL); signal_emit(rec->notice ? "command notice" : "command msg", 3, str, server, item); g_free(str); diff --git a/src/fe-common/core/fe-windows.h b/src/fe-common/core/fe-windows.h index 32d6cfcd..aaa773c8 100644 --- a/src/fe-common/core/fe-windows.h +++ b/src/fe-common/core/fe-windows.h @@ -11,6 +11,14 @@ enum { DATA_LEVEL_HILIGHT }; +enum { + MAIN_WINDOW_TYPE_NONE = -1, + MAIN_WINDOW_TYPE_DEFAULT = 0, + MAIN_WINDOW_TYPE_HIDDEN = 1, + MAIN_WINDOW_TYPE_SPLIT = 2, + MAIN_WINDOW_TYPE_RSPLIT = 3 +}; + typedef struct { char *servertag; char *name; diff --git a/src/fe-common/core/formats.c b/src/fe-common/core/formats.c index 37db6f7c..4c819c2d 100644 --- a/src/fe-common/core/formats.c +++ b/src/fe-common/core/formats.c @@ -480,27 +480,30 @@ int format_real_length(const char *str, int len) start = str; tmp = g_string_new(NULL); - while (*str != '\0' && len > 0) { + while (*str != '\0') { + oldstr = str; if (*str == '%' && str[1] != '\0') { str++; if (*str != '%') { adv = format_expand_styles(tmp, &str, NULL); - str += adv; - if (adv) - continue; - } - - /* %% or unknown %code, written as-is */ - if (*str != '%') { - if (--len == 0) - break; + if (adv) { + str += adv; + continue; + } + /* discount for unknown % */ + if (--len < 0) { + str = oldstr; + break; + } + oldstr = str; } } - oldstr = str; len -= string_advance(&str, utf8); - if (len < 0) + if (len < 0) { str = oldstr; + break; + } } g_string_free(tmp, TRUE); diff --git a/src/fe-common/core/keyboard.c b/src/fe-common/core/keyboard.c index 6f7907eb..c3df5ed7 100644 --- a/src/fe-common/core/keyboard.c +++ b/src/fe-common/core/keyboard.c @@ -156,6 +156,7 @@ static void keyconfig_save(const char *id, const char *key, const char *data) static void keyconfig_clear(const char *key) { CONFIG_NODE *node; + KEY_REC *rec; g_return_if_fail(key != NULL); @@ -165,6 +166,11 @@ static void keyconfig_clear(const char *key) iconfig_node_remove(iconfig_node_traverse("(keyboard", FALSE), node); } + if ((rec = g_hash_table_lookup(default_keys, key)) != NULL) { + node = iconfig_node_traverse("(keyboard", TRUE); + node = iconfig_node_section(node, NULL, NODE_TYPE_BLOCK); + iconfig_node_set_str(node, "key", key); + } } KEYINFO_REC *key_info_find(const char *id) @@ -569,13 +575,38 @@ void key_configure_remove(const char *key) g_return_if_fail(key != NULL); + keyconfig_clear(key); + rec = g_hash_table_lookup(keys, key); if (rec == NULL) return; - keyconfig_clear(key); key_configure_destroy(rec); } +/* Reset key to default */ +void key_configure_reset(const char *key) +{ + KEY_REC *rec; + CONFIG_NODE *node; + + g_return_if_fail(key != NULL); + + node = key_config_find(key); + if (node != NULL) { + iconfig_node_remove(iconfig_node_traverse("(keyboard", FALSE), node); + } + + if ((rec = g_hash_table_lookup(default_keys, key)) != NULL) { + key_configure_create(rec->info->id, rec->key, rec->data); + } else { + rec = g_hash_table_lookup(keys, key); + if (rec == NULL) + return; + + key_configure_destroy(rec); + } +} + static int key_emit_signal(KEYBOARD_REC *keyboard, KEY_REC *key) { int consumed; @@ -739,7 +770,9 @@ static void cmd_show_keys(const char *searchkey, int full) for (key = rec->keys; key != NULL; key = key->next) { KEY_REC *rec = key->data; - if ((len == 0 || g_ascii_strncasecmp(rec->key, searchkey, len) == 0) && + if ((len == 0 || + (full ? strncmp(rec->key, searchkey, len) == 0 : + g_ascii_strncasecmp(rec->key, searchkey, len) == 0)) && (!full || rec->key[len] == '\0')) { printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_BIND_LIST, rec->key, rec->info->id, rec->data == NULL ? "" : rec->data); @@ -750,7 +783,7 @@ static void cmd_show_keys(const char *searchkey, int full) printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_BIND_FOOTER); } -/* SYNTAX: BIND [-list] [-delete] [<key> [<command> [<data>]]] */ +/* SYNTAX: BIND [-list] [-delete | -reset] [<key> [<command> [<data>]]] */ static void cmd_bind(const char *data) { GHashTable *optlist; @@ -780,6 +813,12 @@ static void cmd_bind(const char *data) key_configure_remove(key); cmd_params_free(free_arg); return; + } else if (*key != '\0' && g_hash_table_lookup(optlist, "reset")) { + /* reset key */ + key_configure_reset(key); + cmd_show_keys(key, TRUE); + cmd_params_free(free_arg); + return; } if (*id == '\0') { @@ -878,8 +917,13 @@ static void key_config_read(CONFIG_NODE *node) id = config_node_get_str(node, "id", NULL); data = config_node_get_str(node, "data", NULL); - if (key != NULL && id != NULL) + if (key != NULL && id != NULL) { key_configure_create(id, key, data); + } else if (key != NULL && id == NULL && data == NULL) { + KEY_REC *rec = g_hash_table_lookup(keys, key); + if (rec != NULL) + key_configure_destroy(rec); + } } static void read_keyboard_config(void) @@ -938,7 +982,7 @@ void keyboard_init(void) signal_add("complete command bind", (SIGNAL_FUNC) sig_complete_bind); command_bind("bind", NULL, (SIGNAL_FUNC) cmd_bind); - command_set_options("bind", "delete list"); + command_set_options("bind", "delete reset list"); } void keyboard_deinit(void) diff --git a/src/fe-common/core/themes.c b/src/fe-common/core/themes.c index cb1cce8f..e9818be9 100644 --- a/src/fe-common/core/themes.c +++ b/src/fe-common/core/themes.c @@ -130,7 +130,7 @@ static char *theme_replace_expand(THEME_REC *theme, int index, abstract = rec->data; abstract = theme_format_expand_data(theme, (const char **) &abstract, default_fg, default_bg, - last_fg, last_bg, flags); + last_fg, last_bg, (flags | EXPAND_FLAG_IGNORE_REPLACES)); ret = parse_special_string(abstract, NULL, NULL, data, NULL, PARSE_FLAG_ONLY_ARGS); g_free(abstract); @@ -382,7 +382,8 @@ char *theme_format_expand_get(THEME_REC *theme, const char **format) } else { theme_format_append_next(theme, str, format, reset, reset, - &dummy, &dummy, 0); + &dummy, &dummy, + EXPAND_FLAG_IGNORE_REPLACES); continue; } @@ -400,16 +401,19 @@ char *theme_format_expand_get(THEME_REC *theme, const char **format) return ret; } +static char *theme_format_expand_data_rec(THEME_REC *theme, const char **format, + theme_rm_col default_fg, theme_rm_col default_bg, + theme_rm_col *save_last_fg, theme_rm_col *save_last_bg, + int flags, GTree *block_list); + /* expand a single {abstract ...data... } */ -static char *theme_format_expand_abstract(THEME_REC *theme, - const char **formatp, - theme_rm_col *last_fg, - theme_rm_col *last_bg, - int flags) +static char *theme_format_expand_abstract(THEME_REC *theme, const char **formatp, + theme_rm_col *last_fg, theme_rm_col *last_bg, int flags, + GTree *block_list) { GString *str; const char *p, *format; - char *abstract, *data, *ret; + char *abstract, *data, *ret, *blocking; theme_rm_col default_fg, default_bg; int len; @@ -439,12 +443,22 @@ static char *theme_format_expand_abstract(THEME_REC *theme, } *formatp = format+len; + if (block_list == NULL) { + block_list = g_tree_new_full((GCompareDataFunc) g_strcmp0, NULL, g_free, NULL); + } else { + g_tree_ref(block_list); + } + /* get the abstract data */ data = g_hash_table_lookup(theme->abstracts, abstract); - g_free(abstract); - if (data == NULL) { + if (data == NULL || g_tree_lookup(block_list, abstract) != NULL) { /* unknown abstract, just display the data */ data = "$0-"; + g_free(abstract); + blocking = NULL; + } else { + blocking = abstract; + g_tree_insert(block_list, blocking, blocking); } abstract = g_strdup(data); @@ -473,7 +487,7 @@ static char *theme_format_expand_abstract(THEME_REC *theme, str = g_string_new(NULL); p = ret; while (*p != '\0') { - if (*p == '\\') { + if (*p == '\\' && p[1] != '\0') { int chr; p++; chr = expand_escape(&p); @@ -488,18 +502,20 @@ static char *theme_format_expand_abstract(THEME_REC *theme, /* abstract may itself contain abstracts or replaces */ p = abstract; - ret = theme_format_expand_data(theme, &p, default_fg, default_bg, - last_fg, last_bg, - flags | EXPAND_FLAG_LASTCOLOR_ARG); + ret = theme_format_expand_data_rec(theme, &p, default_fg, default_bg, last_fg, last_bg, + flags | EXPAND_FLAG_LASTCOLOR_ARG, block_list); g_free(abstract); + if (blocking != NULL) { + g_tree_remove(block_list, blocking); + } + g_tree_unref(block_list); return ret; } -/* expand the data part in {abstract data} */ -char *theme_format_expand_data(THEME_REC *theme, const char **format, - theme_rm_col default_fg, theme_rm_col default_bg, - theme_rm_col *save_last_fg, theme_rm_col *save_last_bg, - int flags) +static char *theme_format_expand_data_rec(THEME_REC *theme, const char **format, + theme_rm_col default_fg, theme_rm_col default_bg, + theme_rm_col *save_last_fg, theme_rm_col *save_last_bg, + int flags, GTree *block_list) { GString *str; char *ret, *abstract; @@ -545,9 +561,8 @@ char *theme_format_expand_data(THEME_REC *theme, const char **format, break; /* error */ /* get a single {...} */ - abstract = theme_format_expand_abstract(theme, format, - &last_fg, &last_bg, - recurse_flags); + abstract = theme_format_expand_abstract(theme, format, &last_fg, &last_bg, + recurse_flags, block_list); if (abstract != NULL) { g_string_append(str, abstract); g_free(abstract); @@ -565,6 +580,15 @@ char *theme_format_expand_data(THEME_REC *theme, const char **format, return ret; } +/* expand the data part in {abstract data} */ +char *theme_format_expand_data(THEME_REC *theme, const char **format, theme_rm_col default_fg, + theme_rm_col default_bg, theme_rm_col *save_last_fg, + theme_rm_col *save_last_bg, int flags) +{ + return theme_format_expand_data_rec(theme, format, default_fg, default_bg, save_last_bg, + save_last_bg, flags, NULL); +} + #define IS_OLD_FORMAT(code, last_fg, last_bg) \ (((code) == 'n' && (last_fg) == 'n' && (last_bg) == 'n') || \ ((code) != 'n' && ((code) == (last_fg) || (code) == (last_bg)))) diff --git a/src/fe-common/core/window-commands.c b/src/fe-common/core/window-commands.c index 57c81ac2..a81c0180 100644 --- a/src/fe-common/core/window-commands.c +++ b/src/fe-common/core/window-commands.c @@ -169,7 +169,7 @@ static void cmd_window(const char *data, void *server, WI_ITEM_REC *item) command_runsub("window", data, server, item); } -/* SYNTAX: WINDOW NEW [HIDDEN|SPLIT] */ +/* SYNTAX: WINDOW NEW [HIDDEN|SPLIT|RSPLIT] */ static void cmd_window_new(const char *data, void *server, WI_ITEM_REC *item) { WINDOW_REC *window; @@ -177,8 +177,9 @@ static void cmd_window_new(const char *data, void *server, WI_ITEM_REC *item) g_return_if_fail(data != NULL); - type = (g_ascii_strncasecmp(data, "hid", 3) == 0 || g_ascii_strcasecmp(data, "tab") == 0) ? 1 : - (g_ascii_strcasecmp(data, "split") == 0 ? 2 : 0); + type = (g_ascii_strncasecmp(data, "hid", 3) == 0 || g_ascii_strcasecmp(data, "tab") == 0) ? MAIN_WINDOW_TYPE_HIDDEN : + g_ascii_strcasecmp(data, "split") == 0 ? MAIN_WINDOW_TYPE_SPLIT : + g_ascii_strncasecmp(data, "rs", 2) == 0 ? MAIN_WINDOW_TYPE_RSPLIT : MAIN_WINDOW_TYPE_DEFAULT; signal_emit("gui window create override", 1, GINT_TO_POINTER(type)); window = window_create(NULL, FALSE); diff --git a/src/fe-common/core/window-items.c b/src/fe-common/core/window-items.c index bd6ae5e9..8eab7124 100644 --- a/src/fe-common/core/window-items.c +++ b/src/fe-common/core/window-items.c @@ -314,7 +314,7 @@ void window_item_create(WI_ITEM_REC *item, int automatic) /* create new window to use */ if (settings_get_bool("autocreate_split_windows")) { signal_emit("gui window create override", 1, - GINT_TO_POINTER(0)); + GINT_TO_POINTER(MAIN_WINDOW_TYPE_SPLIT)); } window = window_create(item, automatic); } else { |