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

[WIP] Feature/combi bang anywhere #1124

Draft
wants to merge 7 commits into
base: next
Choose a base branch
from
Draft
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: 2 additions & 0 deletions config/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ Settings config = {
.plugin_path = PLUGIN_PATH,
.max_history_size = 25,
.combi_hide_mode_prefix = FALSE,
/** Combi bang anywhere */
.combi_bang_anywhere = FALSE,

.matching_negate_char = '-',

Expand Down
2 changes: 2 additions & 0 deletions include/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ typedef struct
/** Maximum history length per mode. */
unsigned int max_history_size;
gboolean combi_hide_mode_prefix;
/** Combi mode bang anywhere */
gboolean combi_bang_anywhere;

char matching_negate_char;

Expand Down
125 changes: 75 additions & 50 deletions source/dialogs/combi.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,36 +150,65 @@ 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.

*bang = NULL;
*rest = g_strdup(input);

if ( input == NULL ) {
return;
}

char *sob = input;
sob = g_utf8_strchr ( input, -1, '!' );
if ( sob == NULL ) {
return;
}
char *prev_char = g_utf8_find_prev_char( input, sob );
if ( !config.combi_bang_anywhere && prev_char != NULL ) {
return;
}
while ( prev_char != NULL && !g_unichar_isspace ( g_utf8_get_char( prev_char ) ) ) {
sob = g_utf8_next_char ( sob );
if ( sob == NULL ) {
return;
}
sob = g_utf8_strchr ( sob, -1, '!' );
if ( sob == NULL ) {
return;
}
prev_char = g_utf8_find_prev_char( input, sob );
}

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

*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;
g_free(*rest);
*rest = g_strdup_printf ( "%s%s", head, tail );
g_free(head);
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;
}
}
}
if ( switcher >= 0 ) {
if ( eob[0] == ' ' ) {
char *n = eob + 1;
return mode_result ( pd->switchers[switcher].mode, mretv, &n,
selected_line - pd->starts[switcher] );
}
return MODE_EXIT;
}
}
if ( mretv & MENU_QUICK_SWITCH ) {
return mretv & MENU_LOWER_MASK;
}
Expand Down Expand Up @@ -274,36 +303,32 @@ 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); */
ssize_t bang_len = g_utf8_strlen(bang, -1);
if ( bang != NULL ) {
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 =
Expand Down
2 changes: 2 additions & 0 deletions source/xrmoptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ static XrmOption xrmOptions[] = {
"Max history size (WARNING: can cause slowdowns when set to high).", CONFIG_DEFAULT },
{ xrm_Boolean, "combi-hide-mode-prefix", { .snum = &config.combi_hide_mode_prefix }, NULL,
"Hide the prefix mode prefix on the combi view.", CONFIG_DEFAULT },
{ xrm_Boolean, "combi-bang-anywhere", { .snum = &config.combi_bang_anywhere }, NULL,
"Allow bang (!) to be used anywhere in the string if it occurs after a space character.", CONFIG_DEFAULT },
{ xrm_Char, "matching-negate-char", { .charc = &config.matching_negate_char }, NULL,
"Set the character used to negate the matching. ('\\0' to disable)", CONFIG_DEFAULT },
{ xrm_String, "cache-dir", { .str = &config.cache_dir }, NULL,
Expand Down