fix: ensure consistent unescaping and space handling
Unescape any character following a backslash. This fixes autocompletion for names with escaped spaces. For example: `/msg Thor\ Odinson hello` Signed-off-by: Michael Vetter <jubalh@iodoru.org>
This commit is contained in:
@@ -550,7 +550,7 @@ strip_arg_quotes(const char* const input)
|
||||
// Unescape and strip quotes
|
||||
GString* unescaped = g_string_new("");
|
||||
for (const char* p = input; *p; p++) {
|
||||
if (*p == '\\' && (*(p + 1) == '"' || *(p + 1) == '\\')) {
|
||||
if (*p == '\\' && (*(p + 1) != '\0')) {
|
||||
p++;
|
||||
g_string_append_c(unescaped, *p);
|
||||
} else if (*p == '"') {
|
||||
|
||||
@@ -237,7 +237,7 @@ autocomplete_complete(Autocomplete ac, const gchar* search_str, gboolean quote,
|
||||
// unescape search string
|
||||
GString* unescaped = g_string_new("");
|
||||
for (const char* p = search_str; *p; p++) {
|
||||
if (*p == '\\' && (*(p + 1) == '"' || *(p + 1) == '\\')) {
|
||||
if (*p == '\\' && (*(p + 1) != '\0')) {
|
||||
p++;
|
||||
}
|
||||
g_string_append_c(unescaped, *p);
|
||||
|
||||
@@ -272,6 +272,15 @@ count_tokens(const char* const string)
|
||||
if (curr_uni == ' ') {
|
||||
if (!in_quotes) {
|
||||
num_tokens++;
|
||||
while (i + 1 < length) {
|
||||
gchar* next_ch = g_utf8_offset_to_pointer(string, i + 1);
|
||||
gunichar next_uni = g_utf8_get_char(next_ch);
|
||||
if (next_uni == ' ') {
|
||||
i++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (curr_uni == '"') {
|
||||
if (in_quotes) {
|
||||
@@ -319,6 +328,18 @@ get_start(const char* const string, int tokens)
|
||||
if (curr_uni == ' ') {
|
||||
if (!in_quotes) {
|
||||
num_tokens++;
|
||||
while (i + 1 < length) {
|
||||
gchar* next_ch = g_utf8_offset_to_pointer(string, i + 1);
|
||||
gunichar next_uni = g_utf8_get_char(next_ch);
|
||||
if (next_uni == ' ') {
|
||||
if (num_tokens <= tokens) {
|
||||
g_string_append_unichar(result, next_uni);
|
||||
}
|
||||
i++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (curr_uni == '"') {
|
||||
if (in_quotes) {
|
||||
|
||||
@@ -345,3 +345,31 @@ autocomplete_complete__returns__regular_ascii(void** state)
|
||||
autocomplete_free(ac);
|
||||
free(result);
|
||||
}
|
||||
|
||||
void
|
||||
autocomplete_complete__handles__escaped_spaces(void** state)
|
||||
{
|
||||
Autocomplete ac = autocomplete_new();
|
||||
autocomplete_add(ac, "Thor Odinson");
|
||||
|
||||
char* result = autocomplete_complete(ac, "Thor\\ ", TRUE, FALSE);
|
||||
|
||||
assert_string_equal("\"Thor Odinson\"", result);
|
||||
|
||||
autocomplete_free(ac);
|
||||
free(result);
|
||||
}
|
||||
|
||||
void
|
||||
autocomplete_complete__handles__escaped_quotes(void** state)
|
||||
{
|
||||
Autocomplete ac = autocomplete_new();
|
||||
autocomplete_add(ac, "Thor \"The Thunderer\" Odinson");
|
||||
|
||||
char* result = autocomplete_complete(ac, "Thor \\\"", TRUE, FALSE);
|
||||
|
||||
assert_string_equal("\"Thor \\\"The Thunderer\\\" Odinson\"", result);
|
||||
|
||||
autocomplete_free(ac);
|
||||
free(result);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
void autocomplete_complete__returns__null_when_empty(void** state);
|
||||
void autocomplete_reset__updates__after_create(void** state);
|
||||
void autocomplete_complete__returns__null_after_create(void** state);
|
||||
void autocomplete_complete__handles__escaped_spaces(void** state);
|
||||
void autocomplete_complete__handles__escaped_quotes(void** state);
|
||||
void autocomplete_create_list__returns__null_after_create(void** state);
|
||||
void autocomplete_add__updates__one_and_complete(void** state);
|
||||
void autocomplete_complete__returns__first_of_two(void** state);
|
||||
|
||||
@@ -342,6 +342,20 @@ parse_args_with_freetext__returns__quoted_freetext(void** state)
|
||||
g_strfreev(args);
|
||||
}
|
||||
|
||||
void
|
||||
parse_args_with_freetext__returns__quoted_start_of_freetext(void** state)
|
||||
{
|
||||
char* inp = "/cmd arg1 \"arg2 with space\" more text";
|
||||
gboolean result = FALSE;
|
||||
gchar** args = parse_args_with_freetext(inp, 1, 2, &result);
|
||||
|
||||
assert_true(result);
|
||||
assert_int_equal(2, g_strv_length(args));
|
||||
assert_string_equal("arg1", args[0]);
|
||||
assert_string_equal("\"arg2 with space\" more text", args[1]);
|
||||
g_strfreev(args);
|
||||
}
|
||||
|
||||
void
|
||||
parse_args_with_freetext__returns__third_arg_quoted(void** state)
|
||||
{
|
||||
@@ -504,6 +518,15 @@ count_tokens__handles__escapes(void** state)
|
||||
assert_int_equal(2, result);
|
||||
}
|
||||
|
||||
void
|
||||
count_tokens__handles__multiple_spaces(void** state)
|
||||
{
|
||||
char* inp = "one two";
|
||||
int result = count_tokens(inp);
|
||||
|
||||
assert_int_equal(2, result);
|
||||
}
|
||||
|
||||
void
|
||||
get_start__returns__first_of_one(void** state)
|
||||
{
|
||||
@@ -574,6 +597,16 @@ get_start__handles__escapes(void** state)
|
||||
g_free(result);
|
||||
}
|
||||
|
||||
void
|
||||
get_start__handles__multiple_spaces(void** state)
|
||||
{
|
||||
char* inp = "one two";
|
||||
char* result = get_start(inp, 2);
|
||||
|
||||
assert_string_equal("one ", result);
|
||||
g_free(result);
|
||||
}
|
||||
|
||||
void
|
||||
parse_options__returns__empty_hashmap_when_none(void** state)
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@ void count_tokens__returns__two_tokens_first_quoted(void** state);
|
||||
void count_tokens__returns__two_tokens_second_quoted(void** state);
|
||||
void count_tokens__returns__two_tokens_both_quoted(void** state);
|
||||
void count_tokens__handles__escapes(void** state);
|
||||
void count_tokens__handles__multiple_spaces(void** state);
|
||||
void get_start__returns__first_of_one(void** state);
|
||||
void get_start__returns__first_of_two(void** state);
|
||||
void get_start__returns__first_two_of_three(void** state);
|
||||
@@ -47,6 +48,7 @@ void get_start__returns__first_two_of_three_first_quoted(void** state);
|
||||
void get_start__returns__first_two_of_three_second_quoted(void** state);
|
||||
void get_start__returns__first_two_of_three_first_and_second_quoted(void** state);
|
||||
void get_start__handles__escapes(void** state);
|
||||
void get_start__handles__multiple_spaces(void** state);
|
||||
void parse_options__returns__empty_hashmap_when_none(void** state);
|
||||
void parse_options__returns__error_when_opt1_no_val(void** state);
|
||||
void parse_options__returns__map_when_one(void** state);
|
||||
|
||||
@@ -120,6 +120,8 @@ main(int argc, char* argv[])
|
||||
cmocka_unit_test(autocomplete_complete__returns__null_when_empty),
|
||||
cmocka_unit_test(autocomplete_reset__updates__after_create),
|
||||
cmocka_unit_test(autocomplete_complete__returns__null_after_create),
|
||||
cmocka_unit_test(autocomplete_complete__handles__escaped_spaces),
|
||||
cmocka_unit_test(autocomplete_complete__handles__escaped_quotes),
|
||||
cmocka_unit_test(autocomplete_create_list__returns__null_after_create),
|
||||
cmocka_unit_test(autocomplete_add__updates__one_and_complete),
|
||||
cmocka_unit_test(autocomplete_complete__returns__first_of_two),
|
||||
@@ -218,6 +220,7 @@ main(int argc, char* argv[])
|
||||
cmocka_unit_test(count_tokens__returns__two_tokens_second_quoted),
|
||||
cmocka_unit_test(count_tokens__returns__two_tokens_both_quoted),
|
||||
cmocka_unit_test(count_tokens__handles__escapes),
|
||||
cmocka_unit_test(count_tokens__handles__multiple_spaces),
|
||||
cmocka_unit_test(get_start__returns__first_of_one),
|
||||
cmocka_unit_test(get_start__returns__first_of_two),
|
||||
cmocka_unit_test(get_start__returns__first_two_of_three),
|
||||
@@ -225,6 +228,7 @@ main(int argc, char* argv[])
|
||||
cmocka_unit_test(get_start__returns__first_two_of_three_second_quoted),
|
||||
cmocka_unit_test(get_start__returns__first_two_of_three_first_and_second_quoted),
|
||||
cmocka_unit_test(get_start__handles__escapes),
|
||||
cmocka_unit_test(get_start__handles__multiple_spaces),
|
||||
cmocka_unit_test(parse_options__returns__empty_hashmap_when_none),
|
||||
cmocka_unit_test(parse_options__returns__error_when_opt1_no_val),
|
||||
cmocka_unit_test(parse_options__returns__map_when_one),
|
||||
|
||||
Reference in New Issue
Block a user