Added option -name-only to match only desktop entry name with drun (#690)

* Added option -name-only to match only desktop entry name with drun

* fixed indent and xrdump test

* fixed test

* option -drun-match-fields

* option -window-match-fields

* matching fields as static in window/drun + enums for field indexes

* prevent window_mode_parse_fields() from executing twice
This commit is contained in:
Askrenteam 2017-10-21 11:18:52 +02:00 committed by Dave Davenport
parent af81a54adf
commit 0dc71fcc00
16 changed files with 355 additions and 116 deletions

View file

@ -114,6 +114,10 @@ Settings config = {
.tokenize = TRUE,
.matching = "normal",
.matching_method = MM_NORMAL,
/** Desktop entry fields to match*/
.drun_match_fields = "all",
/** Window fields to match in window mode*/
.window_match_fields = "all",
/** Monitor */
.monitor = "-5",
/** set line margin */

View file

@ -372,6 +372,61 @@ Note: glob matching might be slow for larger lists
.P
Tokenize the input\.
.
.P
\fB\-drun\-match\-fields\fR \fIfield1\fR,\fIfield2\fR,\.\.\.
.
.P
When using drun, match only with the specified Desktop entry fields\. The different fields are:
.
.IP "\(bu" 4
\fBname\fR: the application\'s name
.
.IP "\(bu" 4
\fBgeneric\fR: the application\'s generic name
.
.IP "\(bu" 4
\fBexec\fR: the application\'s executable
.
.IP "\(bu" 4
\fBcategories\fR: the application\'s categories
.
.IP "\(bu" 4
\fBall\fR: all of the above
.
.IP
Default: \fIall\fR
.
.IP "" 0
.
.P
\fB\-window\-match\-fields\fR \fIfield1\fR,\fIfield2\fR,\.\.\.
.
.P
When using window mode, match only with the specified fields\. The different fields are:
.
.IP "\(bu" 4
\fBtitle\fR: window\'s title
.
.IP "\(bu" 4
\fBclass\fR: window\'s class
.
.IP "\(bu" 4
\fBrole\fR: window\'s role
.
.IP "\(bu" 4
\fBname\fR: window\'s name
.
.IP "\(bu" 4
\fBdesktop\fR: window\'s current desktop
.
.IP "\(bu" 4
\fBall\fR: all of the above
.
.IP
Default: \fIall\fR
.
.IP "" 0
.
.SS "Layout"
Most of the following options are \fBdeprecated\fR and should not be used\. Please use the new theme format to customize \fBrofi\fR\. More information about the new format can be found in the \fBrofi\-theme(5)\fR manpage\.
.

View file

@ -215,6 +215,34 @@ Note: glob matching might be slow for larger lists
Tokenize the input.
`-drun-match-fields` *field1*,*field2*,...
When using drun, match only with the specified Desktop entry fields.
The different fields are:
* **name**: the application's name
* **generic**: the application's generic name
* **exec**: the application's executable
* **categories**: the application's categories
* **all**: all of the above
Default: *all*
`-window-match-fields` *field1*,*field2*,...
When using window mode, match only with the specified fields.
The different fields are:
* **title**: window's title
* **class**: window's class
* **role**: window's role
* **name**: window's name
* **desktop**: window's current desktop
* **all**: all of the above
Default: *all*
### Layout
Most of the following options are **deprecated** and should not be used. Please use the new theme format to customize

View file

@ -36,8 +36,12 @@ rofi.run-command: bash -c "{cmd}"
rofi.run-shell-command: {terminal} -e {cmd}
! "Command executed on accep-entry-custom for window modus" Set from: File
rofi.window-command: xkill -id {window}
! "Window fields to match in window mode" Set from: Default
! rofi.window-match-fields: all
! "Theme to use to look for icons" Set from: Default
! rofi.drun-icon-theme:
! "Desktop entry fields to match in drun" Set from: Default
! rofi.drun-match-fields: all
! "Disable history in run/ssh" Set from: File
rofi.disable-history: false
! "Use sorting" Set from: Default

View file

@ -85,6 +85,8 @@ typedef struct
char * run_list_command;
/** Command for window */
char * window_command;
/** Window fields to match in window mode */
char * window_match_fields;
/** Theme for icons */
char * drun_icon_theme;
@ -102,6 +104,8 @@ typedef struct
unsigned int disable_history;
/** Toggle to enable sorting. */
unsigned int sort;
/** Desktop entries to match in drun */
char * drun_match_fields;
/** Use levenshtein sorting when matching */
unsigned int levenshtein_sort;
/** Search case sensitivity */

View file

@ -90,6 +90,28 @@ typedef struct
gint sort_index;
} DRunModeEntry;
typedef struct
{
const char *entry_field_name;
gboolean enabled;
} DRunEntryField;
typedef enum
{
DRUN_MATCH_FIELD_NAME,
DRUN_MATCH_FIELD_GENERIC,
DRUN_MATCH_FIELD_EXEC,
DRUN_MATCH_FIELD_CATEGORIES,
DRUN_MATCH_NUM_FIELDS,
} DRunMatchingFields;
static DRunEntryField matching_entry_fields[DRUN_MATCH_NUM_FIELDS] = {
{ .entry_field_name = "name", .enabled = TRUE, },
{ .entry_field_name = "generic", .enabled = TRUE, },
{ .entry_field_name = "exec", .enabled = TRUE, },
{ .entry_field_name = "categories", .enabled = TRUE, }
};
typedef struct
{
NkXdgThemeContext *xdg_context;
@ -100,9 +122,9 @@ typedef struct
GHashTable *disabled_entries;
unsigned int disabled_entries_length;
GThreadPool *pool;
unsigned int expected_line_height;
DRunModeEntry quit_entry;
// Theme
const gchar *icon_theme;
} DRunModePrivateData;
@ -112,6 +134,7 @@ struct RegexEvalArg
DRunModeEntry *e;
gboolean success;
};
static gboolean drun_helper_eval_cb ( const GMatchInfo *info, GString *res, gpointer data )
{
// TODO quoting is not right? Find description not very clear, need to check.
@ -554,6 +577,42 @@ static void drun_icon_fetch ( gpointer data, gpointer user_data )
rofi_view_reload ();
}
static void drun_mode_parse_entry_fields ()
{
char *savept = NULL;
// Make a copy, as strtok will modify it.
char *switcher_str = g_strdup ( config.drun_match_fields );
const char * const sep = ",#";
// Split token on ','. This modifies switcher_str.
for ( unsigned int i = 0; i < DRUN_MATCH_NUM_FIELDS; i++ ) {
matching_entry_fields[i].enabled = FALSE;
}
for ( char *token = strtok_r ( switcher_str, sep, &savept ); token != NULL;
token = strtok_r ( NULL, sep, &savept ) ) {
if ( strcmp ( token, "all" ) == 0 ) {
for ( unsigned int i = 0; i < DRUN_MATCH_NUM_FIELDS; i++ ) {
matching_entry_fields[i].enabled = TRUE;
}
break;
}
else {
gboolean matched = FALSE;
for ( unsigned int i = 0; i < DRUN_MATCH_NUM_FIELDS; i++ ) {
const char * entry_name = matching_entry_fields[i].entry_field_name;
if ( strcmp ( token, entry_name ) == 0 ) {
matching_entry_fields[i].enabled = TRUE;
matched = TRUE;
}
}
if ( !matched ) {
g_warning ( "Invalid entry name :%s", token );
}
}
}
// Free string that was modified by strtok_r
g_free ( switcher_str );
}
static int drun_mode_init ( Mode *sw )
{
if ( mode_get_private_data ( sw ) == NULL ) {
@ -572,6 +631,7 @@ static int drun_mode_init ( Mode *sw )
pd->xdg_context = nk_xdg_theme_context_new ( drun_icon_fallback_themes, NULL );
nk_xdg_theme_preload_themes_icon ( pd->xdg_context, themes );
get_apps ( pd );
drun_mode_parse_entry_fields ();
}
return TRUE;
}
@ -713,17 +773,24 @@ static int drun_token_match ( const Mode *data, rofi_int_matcher **tokens, unsig
int test = 0;
rofi_int_matcher *ftokens[2] = { tokens[j], NULL };
// Match name
if ( matching_entry_fields[DRUN_MATCH_FIELD_NAME].enabled ) {
if ( rmpd->entry_list[index].name ) {
test = helper_token_match ( ftokens, rmpd->entry_list[index].name );
}
}
if ( matching_entry_fields[DRUN_MATCH_FIELD_GENERIC].enabled ) {
// Match generic name
if ( test == tokens[j]->invert && rmpd->entry_list[index].generic_name ) {
test = helper_token_match ( ftokens, rmpd->entry_list[index].generic_name );
}
}
if ( matching_entry_fields[DRUN_MATCH_FIELD_EXEC].enabled ) {
// Match executable name.
if ( test == tokens[j]->invert ) {
test = helper_token_match ( ftokens, rmpd->entry_list[index].exec );
}
}
if ( matching_entry_fields[DRUN_MATCH_FIELD_CATEGORIES].enabled ) {
// Match against category.
if ( test == tokens[j]->invert ) {
gchar **list = rmpd->entry_list[index].categories;
@ -731,11 +798,13 @@ static int drun_token_match ( const Mode *data, rofi_int_matcher **tokens, unsig
test = helper_token_match ( ftokens, list[iter] );
}
}
}
if ( test == 0 ) {
match = 0;
}
}
}
return match;
}

View file

@ -54,11 +54,40 @@
#include "widgets/textbox.h"
#include "dialogs/window.h"
#include "timings.h"
#define WINLIST 32
#define CLIENTSTATE 10
#define CLIENTWINDOWTYPE 10
// Fields to match in window mode
typedef struct
{
char *field_name;
gboolean enabled;
} WinModeField;
typedef enum
{
WIN_MATCH_FIELD_TITLE,
WIN_MATCH_FIELD_CLASS,
WIN_MATCH_FIELD_ROLE,
WIN_MATCH_FIELD_NAME,
WIN_MATCH_FIELD_DESKTOP,
WIN_MATCH_NUM_FIELDS,
} WinModeMatchingFields;
static WinModeField matching_window_fields[WIN_MATCH_NUM_FIELDS] = {
{ .field_name = "title", .enabled = TRUE, },
{ .field_name = "class", .enabled = TRUE, },
{ .field_name = "role", .enabled = TRUE, },
{ .field_name = "name", .enabled = TRUE, },
{ .field_name = "desktop", .enabled = TRUE, }
};
static gboolean window_matching_fields_parsed = FALSE;
// a manageable window
typedef struct
{
@ -344,22 +373,22 @@ static int window_match ( const Mode *sw, rofi_int_matcher **tokens, unsigned in
// If hack not in place it would not match queries spanning multiple fields.
// e.g. when searching 'title element' and 'class element'
rofi_int_matcher *ftokens[2] = { tokens[j], NULL };
if ( c->title != NULL && c->title[0] != '\0' ) {
if ( c->title != NULL && c->title[0] != '\0' && matching_window_fields[WIN_MATCH_FIELD_TITLE].enabled ) {
test = helper_token_match ( ftokens, c->title );
}
if ( test == tokens[j]->invert && c->class != NULL && c->class[0] != '\0' ) {
if ( test == tokens[j]->invert && c->class != NULL && c->class[0] != '\0' && matching_window_fields[WIN_MATCH_FIELD_CLASS].enabled ) {
test = helper_token_match ( ftokens, c->class );
}
if ( test == tokens[j]->invert && c->role != NULL && c->role[0] != '\0' ) {
if ( test == tokens[j]->invert && c->role != NULL && c->role[0] != '\0' && matching_window_fields[WIN_MATCH_FIELD_ROLE].enabled ) {
test = helper_token_match ( ftokens, c->role );
}
if ( test == tokens[j]->invert && c->name != NULL && c->name[0] != '\0' ) {
if ( test == tokens[j]->invert && c->name != NULL && c->name[0] != '\0' && matching_window_fields[WIN_MATCH_FIELD_NAME].enabled ) {
test = helper_token_match ( ftokens, c->name );
}
if ( test == tokens[j]->invert && c->wmdesktopstr != NULL && c->wmdesktopstr[0] != '\0' ) {
if ( test == tokens[j]->invert && c->wmdesktopstr != NULL && c->wmdesktopstr[0] != '\0' && matching_window_fields[WIN_MATCH_FIELD_DESKTOP].enabled ) {
test = helper_token_match ( ftokens, c->wmdesktopstr );
}
@ -372,6 +401,43 @@ static int window_match ( const Mode *sw, rofi_int_matcher **tokens, unsigned in
return match;
}
static void window_mode_parse_fields ()
{
window_matching_fields_parsed = TRUE;
char *savept = NULL;
// Make a copy, as strtok will modify it.
char *switcher_str = g_strdup ( config.window_match_fields );
const char * const sep = ",#";
// Split token on ','. This modifies switcher_str.
for ( unsigned int i = 0; i < WIN_MATCH_NUM_FIELDS; i++ ) {
matching_window_fields[i].enabled = FALSE;
}
for ( char *token = strtok_r ( switcher_str, sep, &savept ); token != NULL;
token = strtok_r ( NULL, sep, &savept ) ) {
if ( strcmp ( token, "all" ) == 0 ) {
for ( unsigned int i = 0; i < WIN_MATCH_NUM_FIELDS; i++ ) {
matching_window_fields[i].enabled = TRUE;
}
break;
}
else {
gboolean matched = FALSE;
for ( unsigned int i = 0; i < WIN_MATCH_NUM_FIELDS; i++ ) {
const char * field_name = matching_window_fields[i].field_name;
if ( strcmp ( token, field_name ) == 0 ) {
matching_window_fields[i].enabled = TRUE;
matched = TRUE;
}
}
if ( !matched ) {
g_warning ( "Invalid window field name :%s", token );
}
}
}
// Free string that was modified by strtok_r
g_free ( switcher_str );
}
static unsigned int window_mode_get_num_entries ( const Mode *sw )
{
const ModeModePrivateData *pd = (const ModeModePrivateData *) mode_get_private_data ( sw );
@ -523,6 +589,9 @@ static int window_mode_init ( Mode *sw )
pd->window_regex = g_regex_new ( "{[-\\w]+(:-?[0-9]+)?}", 0, 0, NULL );
mode_set_private_data ( sw, (void *) pd );
_window_mode_load_data ( sw, FALSE );
if ( !window_matching_fields_parsed ) {
window_mode_parse_fields ();
}
}
return TRUE;
}
@ -533,6 +602,9 @@ static int window_mode_init_cd ( Mode *sw )
pd->window_regex = g_regex_new ( "{[-\\w]+(:-?[0-9]+)?}", 0, 0, NULL );
mode_set_private_data ( sw, (void *) pd );
_window_mode_load_data ( sw, TRUE );
if ( !window_matching_fields_parsed ) {
window_mode_parse_fields ();
}
}
return TRUE;
}

View file

@ -128,9 +128,13 @@ static XrmOption xrmOptions[] = {
"Run command to execute that runs in shell", CONFIG_DEFAULT },
{ xrm_String, "window-command", { .str = &config.window_command }, NULL,
"Command executed on accep-entry-custom for window modus", CONFIG_DEFAULT },
{ xrm_String, "window-match-fields", { .str = &config.window_match_fields }, NULL,
"Window fields to match in window mode", CONFIG_DEFAULT },
{ xrm_String, "drun-icon-theme", { .str = &config.drun_icon_theme }, NULL,
"Theme to use to look for icons", CONFIG_DEFAULT },
{ xrm_String, "drun-match-fields", { .str = &config.drun_match_fields }, NULL,
"Desktop entry fields to match in drun", CONFIG_DEFAULT },
{ xrm_Boolean, "disable-history", { .num = &config.disable_history }, NULL,
"Disable history in run/ssh", CONFIG_DEFAULT },
{ xrm_Boolean, "sort", { .num = &config.sort }, NULL,

View file

@ -28,7 +28,6 @@ tests=(
cd ${MESON_BUILD_ROOT}
mkdir -p test-x-logs
rm -f core
display=200
for test in "${tests[@]}"; do
log_prefix=test-x-logs/${display}