From 6a6242c866c78d6c9f5002043649fdb669ccad78 Mon Sep 17 00:00:00 2001 From: Robert Alm Nilsson Date: Mon, 27 Jul 2020 13:06:06 +0200 Subject: [PATCH 1/2] Search variables using multiple words This makes is possible to search using multiple words in the vars menu. When you do that you will find all variables that contain all of the specified words in any order. Examples: If you search for "weap rifle" you will find: - riflefragweap1 - riflefragweap2 - weapidxrifle If you search for "plasma 1" you will find all variables that modify plasma 1. --- config/menus/vars.cfg | 5 ++++- src/engine/command.cpp | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/config/menus/vars.cfg b/config/menus/vars.cfg index 66bcf8dae..d2f411a9e 100644 --- a/config/menus/vars.cfg +++ b/config/menus/vars.cfg @@ -83,7 +83,10 @@ menu_variables = [ q = (+ $variable_index $i) if (< $q $numvars) [ curvar = (getvarinfo $q $variable_types $variable_no_types $variable_flags $variable_no_flags $variable_search_text) - hilvar = (stringreplace $curvar $variable_search_text (format "^fs^fy%1^fS" $variable_search_text)) + hilvar = $curvar + looplist variable_search_word $variable_search_text [ + hilvar = (stringreplace $hilvar $variable_search_word (format "^fs^fy%1^fS" $variable_search_word)) + ] ui_list [ ui_radiobutton $hilvar variable_number $q ] ] [ ui_strut 1 ] ] diff --git a/src/engine/command.cpp b/src/engine/command.cpp index 705e9577c..4f78a1152 100644 --- a/src/engine/command.cpp +++ b/src/engine/command.cpp @@ -3579,11 +3579,24 @@ void getvarinfo(int n, int types, int notypes, int flags, int noflags, char *str } if(str && *str) { + std::vector words; + explodelist(str, words); static char *laststr = NULL; if(ids[1].empty() || !laststr || strcmp(str, laststr)) { ids[1].setsize(0); - loopv(ids[0]) if(rigcasestr(ids[0][i]->name, str)) ids[1].add(ids[0][i]); + loopv(ids[0]) + { + bool matches = true; + for (const std::string &word : words) + { + if(!rigcasestr(ids[0][i]->name, word.c_str())) + { + matches = false; + } + } + if(matches) ids[1].add(ids[0][i]); + } if(laststr) DELETEA(laststr); laststr = newstring(str); } From d315585f64d6400243fb79e14a053a85edc4d156 Mon Sep 17 00:00:00 2001 From: Robert Alm Nilsson Date: Tue, 28 Jul 2020 16:23:28 +0200 Subject: [PATCH 2/2] Add command string_highlight_list This command helps with the multi word var search highlighting. --- config/menus/vars.cfg | 5 +--- config/usage.cfg | 1 + src/engine/command.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/config/menus/vars.cfg b/config/menus/vars.cfg index d2f411a9e..218760c3c 100644 --- a/config/menus/vars.cfg +++ b/config/menus/vars.cfg @@ -83,10 +83,7 @@ menu_variables = [ q = (+ $variable_index $i) if (< $q $numvars) [ curvar = (getvarinfo $q $variable_types $variable_no_types $variable_flags $variable_no_flags $variable_search_text) - hilvar = $curvar - looplist variable_search_word $variable_search_text [ - hilvar = (stringreplace $hilvar $variable_search_word (format "^fs^fy%1^fS" $variable_search_word)) - ] + hilvar = (string_highlight_list $curvar $variable_search_text "^fs^fy" "^fS") ui_list [ ui_radiobutton $hilvar variable_number $q ] ] [ ui_strut 1 ] ] diff --git a/config/usage.cfg b/config/usage.cfg index afcc7f6cb..7c92d29a1 100644 --- a/config/usage.cfg +++ b/config/usage.cfg @@ -715,6 +715,7 @@ setdesc "stringlen" "returns the length of string;^nexample: stringlen ^"four^"" setdesc "stringncasecmp" "returns true when the first count characters of string1 and string2 are equal ignoring case;^nexample: stringncasecmp ^"str^" ^"StRiNg^" 3" "string1 string2 count" setdesc "stringncmp" "returns true when the first count characters of string1 and string2 are equal;^nexample: stringncmp ^"str^" ^"string^" 3" "string1 string2 count" setdesc "stringreplace" "returns string with all occurrences of search replaced with replace;^nexample: stringreplace ^"misspelled sring^" ^"sring^" ^"string^"" "string search replace" +setdesc "string_highlight_list" "returns string with all occurrences of words in string surrounded by before and after;^nexample: string_highlight_list ^"abcdefghi^" ^"b efg gh^" ^"<^" ^">^" // this returns ^"acdi^"" "string words before after" setdesc "stringstr" "returns the index of search in string;^nexample: stringstr ^"long string^" ^"str^"" "string search" setdesc "substring" "returns a substringing of string starting at start and continuing to the end or for count characters;^nexample: substring ^"string^" 2 3" "string start [count]" setdesc "concat" "returns all values concatenated with a space between each argument;^nexample: concat hello (getname)" "value..." diff --git a/src/engine/command.cpp b/src/engine/command.cpp index 4f78a1152..b3df12ac6 100644 --- a/src/engine/command.cpp +++ b/src/engine/command.cpp @@ -3475,6 +3475,63 @@ char *strreplace(const char *s, const char *oldval, const char *newval) ICOMMAND(0, stringreplace, "sss", (char *s, char *o, char *n), commandret->setstr(strreplace(s, o, n))); +// Surrounds all occurrences in `s` of the words in `words` with `before` and `after`. +// Words that overlap will be merged and count as one big word. +// Example: string_highlight_list("abcdefghi", "b efg gh", "<", ">") +// returns "acdi". +char *string_highlight_list(const char *s, const char *words, const char *before, const char *after) +{ + if(!s || !*s) return newstring(""); + + std::vector word_list; + explodelist(words, word_list); + size_t s_len = strlen(s); + char *highlight_mask = new char[s_len]; // This is a byte array, not string + memset(highlight_mask, 0, s_len); + + // First mark the characters that will be highlighted. + for(const std::string &word : word_list) + { + for(size_t s_i = 0; s_i < s_len; s_i++) + { + char *mp = &highlight_mask[s_i]; + const char *cp = &s[s_i]; + if(strncmp(word.c_str(), cp, word.length()) == 0) + { + memset(mp, 1, word.length()); + } + } + } + + std::string replaced; + replaced.reserve(s_len); + char prev_m = 0; + // Now do the replacing using highlight_mask to see where the highlights start and end. + for(size_t s_i = 0; s_i < s_len; s_i++) + { + char m = highlight_mask[s_i]; + char c = s[s_i]; + // Start highlighting + if(m && !prev_m) + { + replaced += before; + } + // End highlighting + else if(!m && prev_m) + { + replaced += after; + } + replaced += c; + prev_m = m; + } + if(highlight_mask[s_len - 1]) replaced += after; + + delete[] highlight_mask; + return newstring(replaced.c_str(), replaced.length()); +} + +ICOMMAND(0, string_highlight_list, "ssss", (char *s, char *words, char *before, char *after), commandret->setstr(string_highlight_list(s, words, before, after))); + void stringsplice(const char *s, const char *vals, int *skip, int *count) { int slen = strlen(s), vlen = strlen(vals),