-
Notifications
You must be signed in to change notification settings - Fork 614
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
[WIP] Feature/combi bang anywhere #1124
base: next
Are you sure you want to change the base?
Changes from 4 commits
e60ad92
0a3e720
ea0d52e
7b625be
d08b6bf
8c005e0
c2c973b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -150,41 +150,87 @@ static void combi_mode_destroy ( Mode *sw ) | |
mode_set_private_data ( sw, NULL ); | ||
} | ||
} | ||
|
||
static void split_bang( const char *input, char **bang, char **rest ) { | ||
// Splits string input into a part containing the bang and the part containing the rest, | ||
// saved in the pointers bang and rest. | ||
if ( input != NULL) { | ||
char *sob = g_utf8_strchr ( input, -1, '!' ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, it wouldn’t be bad to have a check for |
||
char *prev_char = g_utf8_find_prev_char( input, sob ); | ||
|
||
if (sob != NULL && (prev_char == NULL || ( config.combi_bang_anywhere && prev_char[0] == ' ' ))) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we could reverse the condition with an early return, but it’ll turn a bit ugly, though I’d consider it anyway, would it be my code. |
||
glong sob_offset = g_utf8_pointer_to_offset( input, sob ); | ||
const char *eob = g_utf8_strchr ( sob, -1, ' ' ); | ||
if ( eob == NULL ) { | ||
// Set it to end. | ||
eob = &(input[strlen(input)]); | ||
} | ||
ssize_t bang_len = g_utf8_pointer_to_offset ( sob, eob ); | ||
|
||
if ( bang_len > 1 ) { | ||
*bang = g_utf8_substring( input, sob_offset + 1, sob_offset + bang_len ); | ||
|
||
char *head = g_utf8_substring ( input, 0, ( eob[0] != ' ' && prev_char != NULL) ? sob_offset - 1 : sob_offset ); | ||
const char *tail = ( eob[0] == ' ' ) ? g_utf8_next_char( eob ) : eob; | ||
*rest = g_strdup_printf ( "%s%s", head, tail ); | ||
g_free(head); | ||
return; | ||
} | ||
} | ||
} | ||
*bang = g_strdup(""); | ||
*rest = g_strdup(input); | ||
return; | ||
} | ||
|
||
static ModeMode combi_mode_result ( Mode *sw, int mretv, char **input, unsigned int selected_line ) | ||
{ | ||
CombiModePrivateData *pd = mode_get_private_data ( sw ); | ||
|
||
if ( input[0][0] == '!' ) { | ||
int switcher = -1; | ||
// Implement strchrnul behaviour. | ||
char *eob = g_utf8_strchr ( input[0], -1,' ' ); | ||
if ( eob == NULL ) { | ||
eob = &(input[0][strlen(input[0])]); | ||
} | ||
ssize_t bang_len = g_utf8_pointer_to_offset ( input[0], eob ) - 1; | ||
if ( bang_len > 0 ) { | ||
for ( unsigned i = 0; switcher == -1 && i < pd->num_switchers; i++ ) { | ||
const char *mode_name = mode_get_name ( pd->switchers[i].mode ); | ||
size_t mode_name_len = g_utf8_strlen ( mode_name, -1 ); | ||
if ( (size_t) bang_len <= mode_name_len && utf8_strncmp ( &input[0][1], mode_name, bang_len ) == 0 ) { | ||
switcher = i; | ||
} | ||
} | ||
} | ||
gboolean return_from_fun = FALSE; | ||
ModeMode retv; | ||
char *bang; | ||
char *rest; | ||
split_bang(*input, &bang, &rest); | ||
|
||
ssize_t bang_len = strlen(bang); | ||
if ( bang_len > 0 ) { | ||
int switcher = -1; | ||
for ( unsigned i = 0; switcher == -1 && i < pd->num_switchers; i++ ) { | ||
const char *mode_name = mode_get_name ( pd->switchers[i].mode ); | ||
size_t mode_name_len = g_utf8_strlen ( mode_name, -1 ); | ||
if ( (size_t) bang_len <= mode_name_len && utf8_strncmp ( bang, mode_name, bang_len ) == 0 ) { | ||
switcher = i; | ||
} | ||
} | ||
if ( switcher >= 0 ) { | ||
if ( eob[0] == ' ' ) { | ||
char *n = eob + 1; | ||
return mode_result ( pd->switchers[switcher].mode, mretv, &n, | ||
if ( strlen( rest ) > 0) { | ||
retv = mode_result ( pd->switchers[switcher].mode, mretv, &rest, | ||
selected_line - pd->starts[switcher] ); | ||
return_from_fun = TRUE; | ||
} | ||
return MODE_EXIT; | ||
else { | ||
retv = MODE_EXIT; | ||
return_from_fun = TRUE; | ||
} | ||
} | ||
} | ||
} | ||
|
||
g_free( bang ); | ||
g_free( rest ); | ||
if ( return_from_fun ) { | ||
return retv; | ||
} | ||
|
||
if ( mretv & MENU_QUICK_SWITCH ) { | ||
return mretv & MENU_LOWER_MASK; | ||
} | ||
|
||
unsigned offset = 0; | ||
for ( unsigned i = 0; i < pd->num_switchers; i++ ) { | ||
if ( pd->switchers[i].disable ) { | ||
offset += pd->lengths[i]; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don’t see There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was in fact a leftover from when I first started working on it. In fact, all the previous code that was there to handle the bang seems superfluous. And actually not correct if there are multiple matching modes. |
||
if ( selected_line >= pd->starts[i] && | ||
selected_line < ( pd->starts[i] + pd->lengths[i] ) ) { | ||
return mode_result ( pd->switchers[i].mode, mretv, input, selected_line - pd->starts[i] ); | ||
|
@@ -274,36 +320,31 @@ static cairo_surface_t * combi_get_icon ( const Mode *sw, unsigned int index, in | |
return NULL; | ||
} | ||
|
||
|
||
static char * combi_preprocess_input ( Mode *sw, const char *input ) | ||
{ | ||
CombiModePrivateData *pd = mode_get_private_data ( sw ); | ||
for ( unsigned i = 0; i < pd->num_switchers; i++ ) { | ||
pd->switchers[i].disable = FALSE; | ||
} | ||
if ( input != NULL && input[0] == '!' ) { | ||
// Implement strchrnul behaviour. | ||
const char *eob = g_utf8_strchr ( input, -1, ' ' ); | ||
if ( eob == NULL ) { | ||
// Set it to end. | ||
eob = &(input[strlen(input)]); | ||
} | ||
ssize_t bang_len = g_utf8_pointer_to_offset ( input, eob ) - 1; | ||
if ( bang_len > 0 ) { | ||
for ( unsigned i = 0; i < pd->num_switchers; i++ ) { | ||
const char *mode_name = mode_get_name ( pd->switchers[i].mode ); | ||
size_t mode_name_len = g_utf8_strlen ( mode_name, -1 ); | ||
if ( !( (size_t) bang_len <= mode_name_len && utf8_strncmp ( &input[1], mode_name, bang_len ) == 0 ) ) { | ||
// No match. | ||
pd->switchers[i].disable = TRUE; | ||
} | ||
} | ||
if ( eob[0] == '\0' || eob[1] == '\0' ) { | ||
return NULL; | ||
} | ||
return g_strdup ( eob + 1 ); | ||
} | ||
} | ||
return g_strdup ( input ); | ||
|
||
char *bang; | ||
char *rest; | ||
split_bang(input, &bang, &rest); | ||
|
||
ssize_t bang_len = strlen(bang); | ||
if ( strlen(bang) > 0 ) { | ||
for ( unsigned i = 0; i < pd->num_switchers; i++ ) { | ||
const char *mode_name = mode_get_name ( pd->switchers[i].mode ); | ||
size_t mode_name_len = g_utf8_strlen ( mode_name, -1 ); | ||
if ( !( (size_t) bang_len <= mode_name_len && utf8_strncmp ( bang, mode_name, bang_len ) == 0 ) ) { | ||
// No match. | ||
pd->switchers[i].disable = TRUE; | ||
} | ||
} | ||
} | ||
g_free(bang); | ||
return rest; | ||
} | ||
|
||
Mode combi_mode = | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An early return would be nicer here. Let
bang
beNULL
if there is none, doesn’t saves much, but having an empty string is hardly needed at all here. (g_free
, just asfree
is a no-op onNULL
.)Not sure on the exact policy concerning rofi, but it’s usually considered safe to use a
goto
in those cases.You put
*bang = NULL;
early, to always set it (it’s cheap anyway, won’t hurt if you overwrite it) and usegoto end;
in the condition. The label being put just before theg_strdup(input)
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to avoid the use of goto.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting
*bang = NULL
means I need to do checks afterward, so for now, I left it as an empty string. I did however rework the function with a lot of early returns.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, you change
strlen(bang) > 0
tobang != NULL
, it’s that big of a change, is it? :-)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, changed that now. Code got slightly more complicated because I found a bug: I was only looking for the first '!', while in fact, the first one could be part of a matching token, so now, we’re looking for the first one that is preceded by a space.