mirror of
https://github.com/lbonn/rofi
synced 2025-02-17 05:18:31 +00:00
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:
parent
af81a54adf
commit
0dc71fcc00
16 changed files with 355 additions and 116 deletions
|
@ -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 */
|
||||
|
|
55
doc/rofi.1
55
doc/rofi.1
|
@ -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\.
|
||||
.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Add table
Reference in a new issue