1
0
Fork 0
mirror of https://github.com/davatorium/rofi.git synced 2024-11-25 13:55:34 -05:00
rofi/source/modes/run.c

614 lines
18 KiB
C
Raw Normal View History

/*
2014-03-01 11:27:52 -05:00
* rofi
*
* MIT/X11 License
2023-01-14 07:02:35 -05:00
* Copyright © 2013-2023 Qball Cow <qball@gmpclient.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
/**
* \ingroup RUNMode
* @{
*/
/** The log domain of this dialog. */
#define G_LOG_DOMAIN "Modes.Run"
#include "config.h"
2014-01-20 18:20:09 -05:00
#include <stdio.h>
2021-08-17 19:16:45 -04:00
#include <stdlib.h>
2021-08-17 19:16:45 -04:00
#include <dirent.h>
#include <errno.h>
2014-03-08 15:35:27 -05:00
#include <limits.h>
#include <signal.h>
#include <string.h>
2021-08-17 19:16:45 -04:00
#include <strings.h>
#include <sys/types.h>
#include <unistd.h>
#include "helper.h"
#include "history.h"
#include "modes/filebrowser.h"
#include "modes/run.h"
2021-08-17 19:16:45 -04:00
#include "rofi.h"
#include "settings.h"
2016-01-07 13:47:37 -05:00
#include "mode-private.h"
#include "rofi-icon-fetcher.h"
2021-08-17 19:16:45 -04:00
#include "timings.h"
/**
2017-11-23 12:41:52 -05:00
* Name of the history file where previously chosen commands are stored.
*/
2024-03-11 07:32:12 -04:00
#define RUN_CACHE_FILE "rofi-4.runcache"
2021-08-17 19:16:45 -04:00
typedef struct {
char *entry;
2024-03-11 07:32:12 -04:00
char *exec;
2021-08-17 19:16:45 -04:00
uint32_t icon_fetch_uid;
uint32_t icon_fetch_size;
2024-03-11 07:04:08 -04:00
gboolean from_history;
2021-08-17 19:16:45 -04:00
/* Surface holding the icon. */
cairo_surface_t *icon;
} RunEntry;
/**
* The internal data structure holding the private data of the Run Mode.
*/
2021-08-17 19:16:45 -04:00
typedef struct {
/** list of available commands. */
RunEntry *cmd_list;
/** Length of the #cmd_list. */
unsigned int cmd_list_length;
/** Current mode. */
gboolean file_complete;
uint32_t selected_line;
char *old_input;
Mode *completer;
char *old_completer_input;
} RunModePrivateData;
/**
* @param cmd The cmd to execute
* @param run_in_term Indicate if command should be run in a terminal
* @param orig The cmd to store in history
*
* Execute command and add to history.
* Exact entries should be stored unquoted any custom or with filename
* should be saved in history quoted.
*/
static gboolean exec_cmd(const char *cmd, int run_in_term, const char *orig) {
2021-08-17 19:16:45 -04:00
GError *error = NULL;
if (!cmd || !cmd[0]) {
return FALSE;
}
gsize lf_cmd_size = 0;
gchar *lf_cmd = g_locale_from_utf8(cmd, -1, NULL, &lf_cmd_size, &error);
if (error != NULL) {
g_warning("Failed to convert command to locale encoding: %s",
error->message);
g_error_free(error);
return FALSE;
}
char *path = g_build_filename(cache_dir, RUN_CACHE_FILE, NULL);
RofiHelperExecuteContext context = {.name = NULL};
2024-03-11 07:32:12 -04:00
char *hist = g_strdup_printf("%s\x1f%s", orig, cmd);
2021-08-17 19:16:45 -04:00
// FIXME: assume startup notification support for terminals
if (helper_execute_command(NULL, lf_cmd, run_in_term,
run_in_term ? &context : NULL)) {
/**
* This happens in non-critical time (After launching app)
* It is allowed to be a bit slower.
*/
2024-03-11 07:32:12 -04:00
history_set(path, hist);
2021-08-17 19:16:45 -04:00
g_free(path);
g_free(lf_cmd);
2024-03-11 07:32:12 -04:00
g_free(hist);
2021-08-17 19:16:45 -04:00
return TRUE;
}
2024-03-11 07:32:12 -04:00
history_remove(path, hist);
g_free(hist);
2021-08-17 19:16:45 -04:00
g_free(path);
g_free(lf_cmd);
return FALSE;
}
/**
* @param cmd The command to remove from history
*
* Remove command from history.
*/
2021-08-17 19:16:45 -04:00
static void delete_entry(const RunEntry *cmd) {
char *path = g_build_filename(cache_dir, RUN_CACHE_FILE, NULL);
2024-03-11 07:32:12 -04:00
char *hist = g_strdup_printf("%s\x1f%s", cmd->entry, cmd->exec);
history_remove(path, hist);
g_free(hist);
2021-08-17 19:16:45 -04:00
g_free(path);
}
/**
* @param a The First key to compare
* @param b The second key to compare
2016-07-29 02:32:34 -04:00
* @param data Unused.
*
* Function used for sorting.
*
2021-08-17 19:16:45 -04:00
* @returns returns less then, equal to and greater than zero is a is less than,
* is a match or greater than b.
*/
2021-08-17 19:16:45 -04:00
static int sort_func(const void *a, const void *b, G_GNUC_UNUSED void *data) {
const RunEntry *astr = (const RunEntry *)a;
const RunEntry *bstr = (const RunEntry *)b;
if (astr->entry == NULL && bstr->entry == NULL) {
return 0;
}
if (astr->entry == NULL) {
return 1;
}
if (bstr->entry == NULL) {
return -1;
}
return g_strcmp0(astr->entry, bstr->entry);
}
2015-01-05 15:53:50 -05:00
/**
* External spider to get list of executables.
*/
2021-08-17 19:16:45 -04:00
static RunEntry *get_apps_external(RunEntry *retv, unsigned int *length,
unsigned int num_favorites) {
int fd = execute_generator(config.run_list_command);
if (fd >= 0) {
FILE *inp = fdopen(fd, "r");
if (inp) {
char *buffer = NULL;
size_t buffer_length = 0;
while (getline(&buffer, &buffer_length, inp) > 0) {
int found = 0;
// Filter out line-end.
if (buffer[strlen(buffer) - 1] == '\n') {
buffer[strlen(buffer) - 1] = '\0';
2015-01-05 15:53:50 -05:00
}
2021-08-17 19:16:45 -04:00
// This is a nice little penalty, but doable? time will tell.
// given num_favorites is max 25.
for (unsigned int j = 0; found == 0 && j < num_favorites; j++) {
if (strcasecmp(buffer, retv[j].entry) == 0) {
found = 1;
}
}
if (found == 1) {
continue;
}
// No duplicate, add it.
retv = g_realloc(retv, ((*length) + 2) * sizeof(RunEntry));
retv[(*length)].entry = g_strdup(buffer);
2024-03-11 07:32:12 -04:00
retv[(*length)].exec = g_shell_quote(buffer);
2024-03-11 07:04:08 -04:00
retv[(*length)].from_history = FALSE;
2021-08-17 19:16:45 -04:00
retv[(*length)].icon = NULL;
retv[(*length)].icon_fetch_uid = 0;
retv[(*length)].icon_fetch_size = 0;
2021-08-17 19:16:45 -04:00
(*length)++;
}
if (buffer != NULL) {
free(buffer);
}
if (fclose(inp) != 0) {
g_warning("Failed to close stdout off executor script: '%s'",
g_strerror(errno));
}
}
}
retv[(*length)].entry = NULL;
2024-03-11 07:32:12 -04:00
retv[(*length)].exec = NULL;
2024-03-11 07:04:08 -04:00
retv[(*length)].from_history = FALSE;
2021-08-17 19:16:45 -04:00
retv[(*length)].icon = NULL;
retv[(*length)].icon_fetch_uid = 0;
retv[(*length)].icon_fetch_size = 0;
2021-08-17 19:16:45 -04:00
return retv;
2015-01-05 15:53:50 -05:00
}
/**
* Internal spider used to get list of executables.
*/
2021-08-17 19:16:45 -04:00
static RunEntry *get_apps(unsigned int *length) {
GError *error = NULL;
RunEntry *retv = NULL;
unsigned int num_favorites = 0;
char *path;
2021-08-17 19:16:45 -04:00
if (g_getenv("PATH") == NULL) {
return NULL;
}
TICK_N("start");
path = g_build_filename(cache_dir, RUN_CACHE_FILE, NULL);
char **hretv = history_get_list(path, length);
retv = (RunEntry *)g_malloc0((*length + 1) * sizeof(RunEntry));
for (unsigned int i = 0; i < *length; i++) {
2024-03-11 07:32:12 -04:00
gchar **rs = g_strsplit(hretv[i], "\x1f", 2);
retv[i].entry = rs[0];
retv[i].exec = rs[1];
if (retv[i].exec == NULL) {
retv[i].exec = g_strdup(rs[0]);
}
2024-03-11 07:04:08 -04:00
retv[i].from_history = TRUE;
2024-03-11 07:32:12 -04:00
g_free(rs);
2021-08-17 19:16:45 -04:00
}
g_free(hretv);
g_free(path);
// Keep track of how many where loaded as favorite.
num_favorites = (*length);
path = g_strdup(g_getenv("PATH"));
gsize l = 0;
gchar *homedir = g_locale_to_utf8(g_get_home_dir(), -1, NULL, &l, &error);
if (error != NULL) {
g_debug("Failed to convert homedir to UTF-8: %s", error->message);
for (unsigned int i = 0; retv[i].entry != NULL; i++) {
g_free(retv[i].entry);
2024-03-11 07:32:12 -04:00
g_free(retv[i].exec);
2021-08-17 19:16:45 -04:00
}
g_free(retv);
g_clear_error(&error);
g_free(homedir);
return NULL;
}
const char *const sep = ":";
char *strtok_savepointer = NULL;
for (const char *dirname = strtok_r(path, sep, &strtok_savepointer);
dirname != NULL; dirname = strtok_r(NULL, sep, &strtok_savepointer)) {
char *fpath = rofi_expand_path(dirname);
DIR *dir = opendir(fpath);
g_debug("Checking path %s for executable.", fpath);
g_free(fpath);
if (dir != NULL) {
struct dirent *dent;
gsize dirn_len = 0;
gchar *dirn = g_locale_to_utf8(dirname, -1, NULL, &dirn_len, &error);
if (error != NULL) {
g_debug("Failed to convert directory name to UTF-8: %s",
error->message);
g_clear_error(&error);
closedir(dir);
continue;
}
gboolean is_homedir = g_str_has_prefix(dirn, homedir);
g_free(dirn);
while ((dent = readdir(dir)) != NULL) {
if (dent->d_type != DT_REG && dent->d_type != DT_LNK &&
dent->d_type != DT_UNKNOWN) {
continue;
}
// Skip dot files.
if (dent->d_name[0] == '.') {
continue;
}
if (is_homedir) {
gchar *full_path = g_build_filename(dirname, dent->d_name, NULL);
gboolean b = g_file_test(full_path, G_FILE_TEST_IS_EXECUTABLE);
g_free(full_path);
2021-08-17 19:16:45 -04:00
if (!b) {
continue;
}
}
2021-08-17 19:16:45 -04:00
gsize name_len;
gchar *name =
g_filename_to_utf8(dent->d_name, -1, NULL, &name_len, &error);
if (error != NULL) {
g_debug("Failed to convert filename to UTF-8: %s", error->message);
g_clear_error(&error);
g_free(name);
continue;
}
// This is a nice little penalty, but doable? time will tell.
// given num_favorites is max 25.
int found = 0;
for (unsigned int j = 0; found == 0 && j < num_favorites; j++) {
if (g_strcmp0(name, retv[j].entry) == 0) {
found = 1;
}
2014-11-06 11:44:41 -05:00
}
2021-08-17 19:16:45 -04:00
if (found == 1) {
g_free(name);
continue;
}
2021-08-17 19:16:45 -04:00
retv = g_realloc(retv, ((*length) + 2) * sizeof(RunEntry));
retv[(*length)].entry = name;
2024-03-11 07:32:12 -04:00
retv[(*length)].exec = g_shell_quote(name);
2024-03-11 07:04:08 -04:00
retv[(*length)].from_history = FALSE;
2021-08-17 19:16:45 -04:00
retv[(*length)].icon = NULL;
retv[(*length)].icon_fetch_uid = 0;
retv[(*length)].icon_fetch_size = 0;
2021-08-17 19:16:45 -04:00
retv[(*length) + 1].entry = NULL;
2024-03-11 07:32:12 -04:00
retv[(*length) + 1].exec = NULL;
2024-03-11 07:04:08 -04:00
retv[(*length) + 1].from_history = FALSE;
2021-08-17 19:16:45 -04:00
retv[(*length) + 1].icon = NULL;
retv[(*length) + 1].icon_fetch_uid = 0;
retv[(*length) + 1].icon_fetch_size = 0;
2021-08-17 19:16:45 -04:00
(*length)++;
}
closedir(dir);
}
}
g_free(homedir);
// Get external apps.
if (config.run_list_command != NULL && config.run_list_command[0] != '\0') {
retv = get_apps_external(retv, length, num_favorites);
}
// No sorting needed.
if ((*length) == 0) {
return retv;
2021-08-17 19:16:45 -04:00
}
// TODO: check this is still fast enough. (takes 1ms on laptop.)
if ((*length) > num_favorites) {
g_qsort_with_data(&(retv[num_favorites]), (*length) - num_favorites,
sizeof(RunEntry), sort_func, NULL);
}
g_free(path);
unsigned int removed = 0;
for (unsigned int index = num_favorites; index < ((*length) - 1); index++) {
if (g_strcmp0(retv[index].entry, retv[index + 1].entry) == 0) {
g_free(retv[index].entry);
retv[index].entry = NULL;
2024-03-11 07:32:12 -04:00
g_free(retv[index].exec);
retv[index].exec = NULL;
2021-08-17 19:16:45 -04:00
removed++;
}
}
if ((*length) > num_favorites) {
g_qsort_with_data(&(retv[num_favorites]), (*length) - num_favorites,
sizeof(RunEntry), sort_func, NULL);
}
// Reduce array length;
(*length) -= removed;
TICK_N("stop");
return retv;
}
2021-08-17 19:16:45 -04:00
static int run_mode_init(Mode *sw) {
if (sw->private_data == NULL) {
RunModePrivateData *pd = g_malloc0(sizeof(*pd));
sw->private_data = (void *)pd;
pd->cmd_list = get_apps(&(pd->cmd_list_length));
pd->completer = NULL;
2021-08-17 19:16:45 -04:00
}
2021-08-17 19:16:45 -04:00
return TRUE;
2015-03-27 15:28:53 -04:00
}
2021-08-17 19:16:45 -04:00
static void run_mode_destroy(Mode *sw) {
RunModePrivateData *rmpd = (RunModePrivateData *)sw->private_data;
if (rmpd != NULL) {
for (unsigned int i = 0; i < rmpd->cmd_list_length; i++) {
g_free(rmpd->cmd_list[i].entry);
2024-03-11 07:32:12 -04:00
g_free(rmpd->cmd_list[i].exec);
2021-08-17 19:16:45 -04:00
if (rmpd->cmd_list[i].icon != NULL) {
cairo_surface_destroy(rmpd->cmd_list[i].icon);
}
}
g_free(rmpd->cmd_list);
g_free(rmpd->old_input);
g_free(rmpd->old_completer_input);
if (rmpd->completer != NULL) {
mode_destroy(rmpd->completer);
g_free(rmpd->completer);
}
2021-08-17 19:16:45 -04:00
g_free(rmpd);
sw->private_data = NULL;
}
2016-03-20 05:20:40 -04:00
}
2021-08-17 19:16:45 -04:00
static unsigned int run_mode_get_num_entries(const Mode *sw) {
const RunModePrivateData *rmpd = (const RunModePrivateData *)sw->private_data;
if (rmpd->file_complete) {
return rmpd->completer->_get_num_entries(rmpd->completer);
}
return rmpd->cmd_list_length;
2015-03-27 15:28:53 -04:00
}
2021-08-17 19:16:45 -04:00
static ModeMode run_mode_result(Mode *sw, int mretv, char **input,
unsigned int selected_line) {
RunModePrivateData *rmpd = (RunModePrivateData *)sw->private_data;
ModeMode retv = MODE_EXIT;
gboolean run_in_term = ((mretv & MENU_CUSTOM_ACTION) == MENU_CUSTOM_ACTION);
if (rmpd->file_complete == TRUE) {
retv = RELOAD_DIALOG;
if ((mretv & (MENU_COMPLETE))) {
g_free(rmpd->old_completer_input);
rmpd->old_completer_input = *input;
*input = NULL;
if (rmpd->selected_line < rmpd->cmd_list_length) {
(*input) = g_strdup(rmpd->old_input);
}
rmpd->file_complete = FALSE;
} else if ((mretv & MENU_CANCEL)) {
retv = MODE_EXIT;
} else {
char *path = NULL;
Merging in the Recursive file browser. Squashed commit of the following: commit 92e730076d461622dc81e44e87ec456317514904 Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 11 18:17:12 2023 +0200 [Doc] Add regex filtering to recursivebrowser. commit ee80c8487f9765b1e6e8ab8219a6baea089cf5af Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 11 17:49:29 2023 +0200 [recursivebrowser] Update manpage. commit a24b68f52362aaf1461935c2340e3bf5e31da59d Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 11 17:37:56 2023 +0200 [Mode] Add some extra validating of the mode selected to complete. commit cf497e8685e806521c0f61922827687adce268c9 Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 4 15:12:31 2023 +0200 [Recursive browser] Make completer selectable. commit 722f07a803c28a406d8a610f31a24b3f7247b9ba Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 4 14:36:14 2023 +0200 Add methods for completer to modes. commit 7972420c30275514751802d1ed517a45bbd83da1 Author: Qball Cow <qball@blame.services> Date: Thu Jun 1 21:56:06 2023 +0200 Prepare updates for new APIs. commit dd3035a1a61f8196d394f6867701a0e1b3af30ac Author: Dave Davenport <qball@gmpclient.org> Date: Wed May 10 19:24:48 2023 +0200 [RB] Fix regex and cleanups commit 4d2941caf32dfb946aee54c467c1319c7a89804a Author: Dave Davenport <qball@blame.services> Date: Wed May 10 18:09:54 2023 +0200 [RB] Add (unfinished regex test) commit 848277001fc8cf9afc538067f2afa24a174f8c7f Author: Dave Davenport <qball@blame.services> Date: Wed May 10 17:49:16 2023 +0200 [RB] Pull the scanning into a separate thread. commit f369a7f63f618bbcad10c18e73f7e2b117c515f1 Author: Dave Davenport <qball@gmpclient.org> Date: Wed May 3 18:35:15 2023 +0200 [Recursive File Browser] First test version.
2023-06-12 13:07:00 -04:00
retv = mode_completer_result(rmpd->completer, mretv, input, selected_line,
&path);
2021-08-17 19:16:45 -04:00
if (retv == MODE_EXIT) {
if (path == NULL) {
2024-03-11 07:32:12 -04:00
char *arg = rmpd->cmd_list[rmpd->selected_line].exec;
exec_cmd(arg, run_in_term, rmpd->cmd_list[rmpd->selected_line].entry);
2021-08-17 19:16:45 -04:00
} else {
2024-03-11 07:32:12 -04:00
char *earg = rmpd->cmd_list[rmpd->selected_line].exec;
char *epath = g_shell_quote(path);
char *arg = g_strdup_printf("%s %s", earg, epath);
exec_cmd(arg, run_in_term, arg);
2021-08-17 19:16:45 -04:00
g_free(arg);
g_free(epath);
}
2021-08-17 19:16:45 -04:00
}
g_free(path);
}
2015-03-27 15:28:53 -04:00
return retv;
2021-08-17 19:16:45 -04:00
}
if ((mretv & MENU_OK) && rmpd->cmd_list[selected_line].entry != NULL) {
2024-03-11 07:04:08 -04:00
char *earg = NULL;
2024-03-11 07:32:12 -04:00
earg = rmpd->cmd_list[selected_line].exec;
if (!exec_cmd(earg, run_in_term, rmpd->cmd_list[selected_line].entry)) {
2021-08-17 19:16:45 -04:00
retv = RELOAD_DIALOG;
}
} else if ((mretv & MENU_CUSTOM_INPUT) && *input != NULL &&
*input[0] != '\0') {
if (!exec_cmd(*input, run_in_term, *input)) {
2021-08-17 19:16:45 -04:00
retv = RELOAD_DIALOG;
}
} else if ((mretv & MENU_ENTRY_DELETE) &&
rmpd->cmd_list[selected_line].entry) {
delete_entry(&(rmpd->cmd_list[selected_line]));
// Clear the list.
retv = RELOAD_DIALOG;
run_mode_destroy(sw);
run_mode_init(sw);
} else if (mretv & MENU_CUSTOM_COMMAND) {
retv = (mretv & MENU_LOWER_MASK);
} else if ((mretv & MENU_COMPLETE)) {
retv = RELOAD_DIALOG;
if (selected_line < rmpd->cmd_list_length) {
rmpd->selected_line = selected_line;
g_free(rmpd->old_input);
rmpd->old_input = g_strdup(*input);
if (*input)
g_free(*input);
*input = g_strdup(rmpd->old_completer_input);
Merging in the Recursive file browser. Squashed commit of the following: commit 92e730076d461622dc81e44e87ec456317514904 Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 11 18:17:12 2023 +0200 [Doc] Add regex filtering to recursivebrowser. commit ee80c8487f9765b1e6e8ab8219a6baea089cf5af Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 11 17:49:29 2023 +0200 [recursivebrowser] Update manpage. commit a24b68f52362aaf1461935c2340e3bf5e31da59d Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 11 17:37:56 2023 +0200 [Mode] Add some extra validating of the mode selected to complete. commit cf497e8685e806521c0f61922827687adce268c9 Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 4 15:12:31 2023 +0200 [Recursive browser] Make completer selectable. commit 722f07a803c28a406d8a610f31a24b3f7247b9ba Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 4 14:36:14 2023 +0200 Add methods for completer to modes. commit 7972420c30275514751802d1ed517a45bbd83da1 Author: Qball Cow <qball@blame.services> Date: Thu Jun 1 21:56:06 2023 +0200 Prepare updates for new APIs. commit dd3035a1a61f8196d394f6867701a0e1b3af30ac Author: Dave Davenport <qball@gmpclient.org> Date: Wed May 10 19:24:48 2023 +0200 [RB] Fix regex and cleanups commit 4d2941caf32dfb946aee54c467c1319c7a89804a Author: Dave Davenport <qball@blame.services> Date: Wed May 10 18:09:54 2023 +0200 [RB] Add (unfinished regex test) commit 848277001fc8cf9afc538067f2afa24a174f8c7f Author: Dave Davenport <qball@blame.services> Date: Wed May 10 17:49:16 2023 +0200 [RB] Pull the scanning into a separate thread. commit f369a7f63f618bbcad10c18e73f7e2b117c515f1 Author: Dave Davenport <qball@gmpclient.org> Date: Wed May 3 18:35:15 2023 +0200 [Recursive File Browser] First test version.
2023-06-12 13:07:00 -04:00
const Mode *comp = rofi_get_completer();
if (comp) {
rmpd->completer = mode_create(comp);
mode_init(rmpd->completer);
rmpd->file_complete = TRUE;
}
2021-08-17 19:16:45 -04:00
}
}
return retv;
2015-03-27 15:28:53 -04:00
}
2021-08-17 19:16:45 -04:00
static char *_get_display_value(const Mode *sw, unsigned int selected_line,
G_GNUC_UNUSED int *state,
G_GNUC_UNUSED GList **list, int get_entry) {
const RunModePrivateData *rmpd = (const RunModePrivateData *)sw->private_data;
if (rmpd->file_complete) {
return rmpd->completer->_get_display_value(rmpd->completer, selected_line,
state, list, get_entry);
}
return get_entry ? g_strdup(rmpd->cmd_list[selected_line].entry) : NULL;
}
2021-08-17 19:16:45 -04:00
static int run_token_match(const Mode *sw, rofi_int_matcher **tokens,
unsigned int index) {
const RunModePrivateData *rmpd = (const RunModePrivateData *)sw->private_data;
if (rmpd->file_complete) {
return rmpd->completer->_token_match(rmpd->completer, tokens, index);
}
return helper_token_match(tokens, rmpd->cmd_list[index].entry);
}
2021-08-17 19:16:45 -04:00
static char *run_get_message(const Mode *sw) {
RunModePrivateData *pd = sw->private_data;
if (pd->file_complete) {
if (pd->selected_line < pd->cmd_list_length) {
char *msg = mode_get_message(pd->completer);
if (msg) {
char *retv =
g_strdup_printf("File complete for: %s\n%s",
pd->cmd_list[pd->selected_line].entry, msg);
g_free(msg);
return retv;
}
return g_strdup_printf("File complete for: %s",
pd->cmd_list[pd->selected_line].entry);
}
2021-08-17 19:16:45 -04:00
}
return NULL;
}
2021-08-17 19:16:45 -04:00
static cairo_surface_t *_get_icon(const Mode *sw, unsigned int selected_line,
2022-07-22 18:28:55 -04:00
unsigned int height) {
2021-08-17 19:16:45 -04:00
RunModePrivateData *pd = (RunModePrivateData *)mode_get_private_data(sw);
if (pd->file_complete) {
return pd->completer->_get_icon(pd->completer, selected_line, height);
}
g_return_val_if_fail(pd->cmd_list != NULL, NULL);
RunEntry *dr = &(pd->cmd_list[selected_line]);
if (dr->icon_fetch_uid > 0 && dr->icon_fetch_size == height) {
2021-08-17 19:16:45 -04:00
cairo_surface_t *icon = rofi_icon_fetcher_get(dr->icon_fetch_uid);
return icon;
2021-08-17 19:16:45 -04:00
}
/** lookup icon */
char **str = g_strsplit(dr->entry, " ", 2);
if (str) {
dr->icon_fetch_uid = rofi_icon_fetcher_query(str[0], height);
dr->icon_fetch_size = height;
2021-08-17 19:16:45 -04:00
g_strfreev(str);
cairo_surface_t *icon = rofi_icon_fetcher_get(dr->icon_fetch_uid);
return icon;
2021-08-17 19:16:45 -04:00
}
return NULL;
}
2016-01-07 15:27:20 -05:00
#include "mode-private.h"
2021-08-17 19:16:45 -04:00
Mode run_mode = {.name = "run",
.cfg_name_key = "display-run",
._init = run_mode_init,
._get_num_entries = run_mode_get_num_entries,
._result = run_mode_result,
._destroy = run_mode_destroy,
._token_match = run_token_match,
._get_message = run_get_message,
._get_display_value = _get_display_value,
._get_icon = _get_icon,
._get_completion = NULL,
._preprocess_input = NULL,
.private_data = NULL,
Merging in the Recursive file browser. Squashed commit of the following: commit 92e730076d461622dc81e44e87ec456317514904 Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 11 18:17:12 2023 +0200 [Doc] Add regex filtering to recursivebrowser. commit ee80c8487f9765b1e6e8ab8219a6baea089cf5af Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 11 17:49:29 2023 +0200 [recursivebrowser] Update manpage. commit a24b68f52362aaf1461935c2340e3bf5e31da59d Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 11 17:37:56 2023 +0200 [Mode] Add some extra validating of the mode selected to complete. commit cf497e8685e806521c0f61922827687adce268c9 Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 4 15:12:31 2023 +0200 [Recursive browser] Make completer selectable. commit 722f07a803c28a406d8a610f31a24b3f7247b9ba Author: Dave Davenport <qball@gmpclient.org> Date: Sun Jun 4 14:36:14 2023 +0200 Add methods for completer to modes. commit 7972420c30275514751802d1ed517a45bbd83da1 Author: Qball Cow <qball@blame.services> Date: Thu Jun 1 21:56:06 2023 +0200 Prepare updates for new APIs. commit dd3035a1a61f8196d394f6867701a0e1b3af30ac Author: Dave Davenport <qball@gmpclient.org> Date: Wed May 10 19:24:48 2023 +0200 [RB] Fix regex and cleanups commit 4d2941caf32dfb946aee54c467c1319c7a89804a Author: Dave Davenport <qball@blame.services> Date: Wed May 10 18:09:54 2023 +0200 [RB] Add (unfinished regex test) commit 848277001fc8cf9afc538067f2afa24a174f8c7f Author: Dave Davenport <qball@blame.services> Date: Wed May 10 17:49:16 2023 +0200 [RB] Pull the scanning into a separate thread. commit f369a7f63f618bbcad10c18e73f7e2b117c515f1 Author: Dave Davenport <qball@gmpclient.org> Date: Wed May 3 18:35:15 2023 +0200 [Recursive File Browser] First test version.
2023-06-12 13:07:00 -04:00
.free = NULL,
.type = MODE_TYPE_SWITCHER};
2020-10-12 15:39:36 -04:00
/** @}*/