string like operation

This commit is contained in:
bagnaram 2024-07-26 14:40:10 -06:00
parent 0f47cbb889
commit 4826a52306
No known key found for this signature in database
GPG key ID: F146C87EF7159A9B
6 changed files with 88 additions and 7 deletions

View file

@ -24,10 +24,13 @@
([#392][392]). ([#392][392]).
* i3/sway: `output` tag, reflecting the output (monitor) a workspace * i3/sway: `output` tag, reflecting the output (monitor) a workspace
is on. is on.
* Added "string like" `~~` operator to Map particle. Allows
glob-style matching on strings using `*` and `?` characters. ([#400][400])
[96]: https://codeberg.org/dnkl/yambar/issues/96 [96]: https://codeberg.org/dnkl/yambar/issues/96
[380]: https://codeberg.org/dnkl/yambar/issues/380 [380]: https://codeberg.org/dnkl/yambar/issues/380
[392]: https://codeberg.org/dnkl/yambar/issues/392 [392]: https://codeberg.org/dnkl/yambar/issues/392
[400]: https://codeberg.org/dnkl/yambar/pulls/400
### Changed ### Changed

View file

@ -265,6 +265,26 @@ To match for empty strings, use ' "" ':
<tag> == "" <tag> == ""
``` ```
String glob matching
To perform string matching using globbing with "\*" & "?" characters:
\* Match any zero or more characters.
? Match exactly any one character.
```
<tag> ~~ "hello*"
```
Will match any string starting with "hello", including "hello",
"hello1", "hello123", etc.
```
<tag> ~~ "hello?"
```
Will match any string starting with "hello" followed by any single
character, including "hello1", "hello-", but not "hello".
Furthermore, you may use the boolean operators: Furthermore, you may use the boolean operators:
[- && [- &&

View file

@ -13,6 +13,59 @@
#include "map.h" #include "map.h"
// String globbing match.
// Note: Uses "non-greedy" implementation for "*" wildcard matching
static bool
string_like(const char* name, const char* pattern)
{
LOG_DBG("pattern:%s name:%s", pattern, name);
int px = 0, nx = 0;
int nextpx = 0, nextnx = 0;
while(px < strlen(pattern) || nx < strlen(name))
{
if(px < strlen(pattern))
{
char c = pattern[px];
switch (c) {
case '?': {
// single character
px++;
nx++;
continue;
}
case '*': {
// zero or more glob
nextpx=px;
nextnx=nx+1;
px++;
continue;
}
default: {
// normal character
if (nx < strlen(name) && name[nx] == c)
{
px++;
nx++;
continue;
}
}
}
}
// mismatch
if (0 < nextnx && nextnx <= strlen(name)) {
px = nextpx;
nx = nextnx;
continue;
}
return false;
}
LOG_DBG("map: name %s matched all the pattern %s", name, pattern);
// Matched all of pattern to all of name. Success.
return true;
}
static bool static bool
int_condition(const long tag_value, const long cond_value, enum map_op op) int_condition(const long tag_value, const long cond_value, enum map_op op)
{ {
@ -75,6 +128,8 @@ str_condition(const char *tag_value, const char *cond_value, enum map_op op)
return strcmp(tag_value, cond_value) >= 0; return strcmp(tag_value, cond_value) >= 0;
case MAP_OP_GT: case MAP_OP_GT:
return strcmp(tag_value, cond_value) > 0; return strcmp(tag_value, cond_value) > 0;
case MAP_OP_LIKE:
return string_like(tag_value, cond_value) != 0;
case MAP_OP_SELF: case MAP_OP_SELF:
LOG_WARN("using String tag as bool"); LOG_WARN("using String tag as bool");
default: default:
@ -166,6 +221,7 @@ free_map_condition(struct map_condition *c)
case MAP_OP_LE: case MAP_OP_LE:
case MAP_OP_LT: case MAP_OP_LT:
case MAP_OP_GE: case MAP_OP_GE:
case MAP_OP_LIKE:
case MAP_OP_GT: case MAP_OP_GT:
free(c->value); free(c->value);
/* FALLTHROUGH */ /* FALLTHROUGH */

View file

@ -9,6 +9,7 @@ enum map_op {
MAP_OP_GT, MAP_OP_GT,
MAP_OP_SELF, MAP_OP_SELF,
MAP_OP_NOT, MAP_OP_NOT,
MAP_OP_LIKE,
MAP_OP_AND, MAP_OP_AND,
MAP_OP_OR, MAP_OP_OR,

View file

@ -69,6 +69,7 @@ void yyerror(const char *s);
\< yylval.op = MAP_OP_LT; return CMP_OP; \< yylval.op = MAP_OP_LT; return CMP_OP;
>= yylval.op = MAP_OP_GE; return CMP_OP; >= yylval.op = MAP_OP_GE; return CMP_OP;
> yylval.op = MAP_OP_GT; return CMP_OP; > yylval.op = MAP_OP_GT; return CMP_OP;
~~ yylval.op = MAP_OP_LIKE; return CMP_OP;
&& yylval.op = MAP_OP_AND; return BOOL_OP; && yylval.op = MAP_OP_AND; return BOOL_OP;
\|\| yylval.op = MAP_OP_OR; return BOOL_OP; \|\| yylval.op = MAP_OP_OR; return BOOL_OP;
~ return NOT; ~ return NOT;

View file

@ -79,7 +79,7 @@ static char const*
token_to_str(yysymbol_kind_t tkn) token_to_str(yysymbol_kind_t tkn)
{ {
switch (tkn) { switch (tkn) {
case YYSYMBOL_CMP_OP: return "==, !=, <=, <, >=, >"; case YYSYMBOL_CMP_OP: return "==, !=, <=, <, >=, >, ~~";
case YYSYMBOL_BOOL_OP: return "||, &&"; case YYSYMBOL_BOOL_OP: return "||, &&";
case YYSYMBOL_L_PAR: return "("; case YYSYMBOL_L_PAR: return "(";
case YYSYMBOL_R_PAR: return ")"; case YYSYMBOL_R_PAR: return ")";