Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search variables using multiple words #168

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/menus/vars.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +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 = (stringreplace $curvar $variable_search_text (format "^fs^fy%1^fS" $variable_search_text))
hilvar = (string_highlight_list $curvar $variable_search_text "^fs^fy" "^fS")
ui_list [ ui_radiobutton $hilvar variable_number $q ]
] [ ui_strut 1 ]
]
Expand Down
1 change: 1 addition & 0 deletions config/usage.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -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 ^"a<b>cd<efgh>i^"" "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..."
Expand Down
72 changes: 71 additions & 1 deletion src/engine/command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 "a<b>cd<efgh>i".
char *string_highlight_list(const char *s, const char *words, const char *before, const char *after)
{
if(!s || !*s) return newstring("");

std::vector<std::string> 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),
Expand Down Expand Up @@ -3579,11 +3636,24 @@ void getvarinfo(int n, int types, int notypes, int flags, int noflags, char *str
}
if(str && *str)
{
std::vector<std::string> 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])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please do not use loop macros, instead use for (int i = 0; i < ids[0].length(); i++)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't add that loop macro. I think getting rid of the loop macros is a separate issue for another PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I general we usually just remove them from code we rework/work at. It doesn't hurt anybody

{
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);
}
Expand Down