summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Davenport <qball@blame.services>2023-01-22 17:25:36 +0100
committerDave Davenport <qball@blame.services>2023-01-22 17:25:36 +0100
commitc84f7f3bad21b984540a00b2815602b7426dae3e (patch)
tree8bd25e47766724f1c7737671d33e8457e811f6ff
parent004f4ebd984311fac47569a54a3bb5cbe395cd6e (diff)
parent6caece77d4cc0fa81b3303a4126e4efbb93b41be (diff)
Merge remote-tracking branch 'github/next' into next
-rw-r--r--doc/rofi-keys.514
-rw-r--r--doc/rofi-keys.5.markdown10
-rw-r--r--doc/rofi.122
-rw-r--r--doc/rofi.1.markdown16
-rw-r--r--include/helper.h2
-rw-r--r--include/keyb.h2
-rw-r--r--include/widgets/textbox.h14
-rw-r--r--source/helper.c11
-rw-r--r--source/keyb.c8
-rw-r--r--source/modes/script.c15
-rw-r--r--source/view.c133
-rw-r--r--source/widgets/textbox.c9
-rw-r--r--test/mode-test.c2
13 files changed, 246 insertions, 12 deletions
diff --git a/doc/rofi-keys.5 b/doc/rofi-keys.5
index 7d0ed990..00174a27 100644
--- a/doc/rofi-keys.5
+++ b/doc/rofi-keys.5
@@ -587,6 +587,20 @@ Select row 10
.PP
\fBDefault\fP: Super+0
+.SS \fBkb-entry-history-up\fP
+.PP
+Go up in the entry history.
+
+.PP
+\fBDefault\fP: Control+Up
+
+.SS \fBkb-entry-history-down\fP
+.PP
+Go down in the entry history.
+
+.PP
+\fBDefault\fP: Control+Down
+
.SH Mouse Bindings
.SS \fBml-row-left\fP
.PP
diff --git a/doc/rofi-keys.5.markdown b/doc/rofi-keys.5.markdown
index c23abb6d..4ff3ae08 100644
--- a/doc/rofi-keys.5.markdown
+++ b/doc/rofi-keys.5.markdown
@@ -415,6 +415,16 @@ Select row 10
**Default**: Super+0
+### **kb-entry-history-up**
+Go up in the entry history.
+
+**Default**: Control+Up
+
+### **kb-entry-history-down**
+Go down in the entry history.
+
+**Default**: Control+Down
+
## Mouse Bindings
### **ml-row-left**
diff --git a/doc/rofi.1 b/doc/rofi.1
index 115dd38b..493751fa 100644
--- a/doc/rofi.1
+++ b/doc/rofi.1
@@ -1180,6 +1180,28 @@ rofi -filebrowser-cancel-returns-1 true -show filebrowser
.PP
The \fB\fCshow-hidden\fR can also be triggered with the \fB\fCkb-delete-entry\fR keybinding.
+.SS Entry history
+.PP
+The number of previous inputs for the entry box can be modified by setting
+max-history on the entry box.
+
+.PP
+.RS
+
+.nf
+configuration {
+ entry {
+ max-history: 30;
+ }
+}
+
+.fi
+.RE
+
+.PP
+By default the file is stored in the systems cache directory, in a file called
+\fB\fCrofi-entry-history.txt\fR\&.
+
.SS Other
.PP
\fB\fC-drun-use-desktop-cache\fR
diff --git a/doc/rofi.1.markdown b/doc/rofi.1.markdown
index b709dd94..94e387fe 100644
--- a/doc/rofi.1.markdown
+++ b/doc/rofi.1.markdown
@@ -726,6 +726,22 @@ rofi -filebrowser-cancel-returns-1 true -show filebrowser
The `show-hidden` can also be triggered with the `kb-delete-entry` keybinding.
+### Entry history
+
+The number of previous inputs for the entry box can be modified by setting
+max-history on the entry box.
+
+```css
+configuration {
+ entry {
+ max-history: 30;
+ }
+}
+```
+
+By default the file is stored in the systems cache directory, in a file called
+`rofi-entry-history.txt`.
+
### Other
`-drun-use-desktop-cache`
diff --git a/include/helper.h b/include/helper.h
index c8a0c01a..146ad46b 100644
--- a/include/helper.h
+++ b/include/helper.h
@@ -397,7 +397,7 @@ char *helper_string_replace_if_exists(char *string, ...);
*
* @returns path to theme or copy of filename if not found.
*/
-char *helper_get_theme_path(const char *file, const char **ext);
+char *helper_get_theme_path(const char *file, const char **ext) __attribute__((nonnull));
/**
* @param name The name of the element to find.
diff --git a/include/keyb.h b/include/keyb.h
index e938ddcc..850df0e6 100644
--- a/include/keyb.h
+++ b/include/keyb.h
@@ -143,6 +143,8 @@ typedef enum {
SELECT_ELEMENT_8,
SELECT_ELEMENT_9,
SELECT_ELEMENT_10,
+ ENTRY_HISTORY_UP,
+ ENTRY_HISTORY_DOWN,
} KeyBindingAction;
/**
diff --git a/include/widgets/textbox.h b/include/widgets/textbox.h
index d5695c0b..01b67a75 100644
--- a/include/widgets/textbox.h
+++ b/include/widgets/textbox.h
@@ -345,5 +345,19 @@ void textbox_set_ellipsize(textbox *tb, PangoEllipsizeMode mode);
* @returns the position of the cursor (0 if no cursor).
*/
int textbox_get_cursor_x_pos(const textbox *tb);
+
+/**
+ * @param tb Handle to the textbox
+ *
+ * @returns gets a newly allocated copy of the content of the entrybox.
+ */
+char *textbox_get_text ( const textbox *tb );
+
+/**
+ * @param tb Handle to the textbox
+ *
+ * @returns the position of the cursor.
+ */
+int textbox_get_cursor ( const textbox *tb );
/**@}*/
#endif // ROFI_TEXTBOX_H
diff --git a/source/helper.c b/source/helper.c
index bc551483..4b14f361 100644
--- a/source/helper.c
+++ b/source/helper.c
@@ -1076,17 +1076,16 @@ char *helper_get_theme_path(const char *file, const char **ext) {
g_free(filename);
gboolean ext_found = FALSE;
- if (ext) {
- for (const char **i = ext; *i != NULL; i++) {
- if (g_str_has_suffix(file, *i)) {
- ext_found = TRUE;
- break;
- }
+ for (const char **i = ext; *i != NULL; i++) {
+ if (g_str_has_suffix(file, *i)) {
+ ext_found = TRUE;
+ break;
}
}
if (ext_found) {
filename = g_strdup(file);
} else {
+ g_assert_nonnull(ext[0]);
// TODO: Pick the first extension. needs fixing.
filename = g_strconcat(file, ext[0], NULL);
}
diff --git a/source/keyb.c b/source/keyb.c
index 1be12167..c30b1d8c 100644
--- a/source/keyb.c
+++ b/source/keyb.c
@@ -324,6 +324,14 @@ ActionBindingEntry rofi_bindings[] = {
.name = "kb-select-10",
.binding = "Super+0",
.comment = "Select row 10"},
+ {.id = ENTRY_HISTORY_UP,
+ .name = "kb-entry-history-up",
+ .binding = "Control+Up",
+ .comment = "Go up in the history of the entry box"},
+ {.id = ENTRY_HISTORY_DOWN,
+ .name = "kb-entry-history-down",
+ .binding = "Control+Down",
+ .comment = "Go down in the history of the entry box"},
/* Mouse-aware bindings */
diff --git a/source/modes/script.c b/source/modes/script.c
index 9da931a6..6661f999 100644
--- a/source/modes/script.c
+++ b/source/modes/script.c
@@ -83,10 +83,13 @@ void dmenuscript_parse_entry_extras(G_GNUC_UNUSED Mode *sw,
DmenuScriptEntry *entry, char *buffer,
G_GNUC_UNUSED size_t length) {
gchar **extras = g_strsplit(buffer, "\x1f", -1);
- gchar **extra;
- for (extra = extras; *extra != NULL && *(extra + 1) != NULL; extra += 2) {
+ gchar **extra = extras;
+ for (; *extra != NULL && *(extra + 1) != NULL; extra += 2) {
gchar *key = *extra;
gchar *value = *(extra + 1);
+ // Mark NULL
+ *(extra) = NULL;
+ *(extra+1) = NULL;
if (strcasecmp(key, "icon") == 0) {
entry->icon_name = value;
} else if (strcasecmp(key, "meta") == 0) {
@@ -107,6 +110,10 @@ void dmenuscript_parse_entry_extras(G_GNUC_UNUSED Mode *sw,
}
g_free(key);
}
+ // Got an extra entry.. lets free it.
+ if ( *extras != NULL ) {
+ g_free(*extras);
+ }
g_free(extras);
}
@@ -247,7 +254,7 @@ static DmenuScriptEntry *execute_executor(Mode *sw, char *arg,
buffer + buf_length,
read_length - buf_length);
}
- retv[(*length) + 1].entry = NULL;
+ memset(&(retv[(*length)+1]), 0, sizeof(DmenuScriptEntry));
(*length)++;
}
}
@@ -350,6 +357,7 @@ static ModeMode script_mode_result(Mode *sw, int mretv, char **input,
g_free(rmpd->cmd_list[i].entry);
g_free(rmpd->cmd_list[i].icon_name);
g_free(rmpd->cmd_list[i].meta);
+ g_free(rmpd->cmd_list[i].info);
}
g_free(rmpd->cmd_list);
@@ -522,6 +530,7 @@ void script_mode_gather_user_scripts(void) {
}
num_scripts++;
}
+ g_dir_close(sd);
}
g_free(script_dir);
diff --git a/source/view.c b/source/view.c
index 9bcd3458..36163168 100644
--- a/source/view.c
+++ b/source/view.c
@@ -48,6 +48,7 @@
#include <cairo-xcb.h>
#include <cairo.h>
+#include <gio/gio.h>
/** Indicated we understand the startup notification api is not yet stable.*/
#define SN_API_NOT_YET_FROZEN
@@ -102,6 +103,11 @@ GThreadPool *tpool = NULL;
/** Global pointer to the currently active RofiViewState */
RofiViewState *current_active_menu = NULL;
+
+typedef struct {
+ char *string;
+ int index;
+} EntryHistoryIndex;
/**
* Structure holding cached state.
*/
@@ -148,6 +154,10 @@ struct {
gboolean fullscreen;
/** Cursor type */
X11CursorType cursor_type;
+ /** Entry box */
+ EntryHistoryIndex *entry_history;
+ gssize entry_history_length;
+ gssize entry_history_index;
} CacheState = {
.main_window = XCB_WINDOW_NONE,
.fake_bg = NULL,
@@ -165,6 +175,9 @@ struct {
.count = 0L,
.repaint_source = 0,
.fullscreen = FALSE,
+ .entry_history = NULL,
+ .entry_history_length = 0,
+ .entry_history_index = 0
};
void rofi_view_get_current_monitor(int *width, int *height) {
@@ -885,7 +898,74 @@ static void open_xim_callback(xcb_xim_t *im, G_GNUC_UNUSED void *user_data) {
}
#endif
+static void input_history_initialize ( void )
+{
+ CacheState.entry_history = NULL;
+ CacheState.entry_history_index = 0;
+ CacheState.entry_history_length = 0;
+
+ gchar *path = g_build_filename(cache_dir, "rofi-entry-history.txt", NULL);
+ if ( g_file_test(path, G_FILE_TEST_EXISTS ) ) {
+ FILE *fp = fopen(path, "r");
+ if ( fp ) {
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t nread;
+ while ((nread = getline(&line, &len, fp)) != -1) {
+ CacheState.entry_history = g_realloc(CacheState.entry_history,
+ sizeof(EntryHistoryIndex)*(CacheState.entry_history_length+1));
+ if ( line[nread-1] == '\n' ) {
+ line[nread-1] = '\0';
+ nread--;
+ }
+ CacheState.entry_history[CacheState.entry_history_length].string = g_strdup(line);
+ CacheState.entry_history[CacheState.entry_history_length].index = strlen(line);
+ CacheState.entry_history_length++;
+ CacheState.entry_history_index++;
+ }
+ free(line);
+ fclose(fp);
+ }
+ }
+ g_free(path);
+ CacheState.entry_history = g_realloc(CacheState.entry_history,
+ sizeof(EntryHistoryIndex)*(CacheState.entry_history_length+1));
+ CacheState.entry_history[CacheState.entry_history_length].string = g_strdup("");
+ CacheState.entry_history[CacheState.entry_history_length].index = 0;
+ CacheState.entry_history_length++;
+
+}
+static void input_history_save ( void )
+{
+ if ( CacheState.entry_history_length > 0 ){
+ // History max.
+ int max_history = 20;
+ ThemeWidget *wid = rofi_config_find_widget("entry", NULL, TRUE);
+ if ( wid ) {
+ Property *p = rofi_theme_find_property(wid, P_INTEGER, "max-history", TRUE);
+ if ( p != NULL && p->type == P_INTEGER ){
+ max_history = p->value.i;
+ }
+ }
+ gchar *path = g_build_filename(cache_dir, "rofi-entry-history.txt", NULL);
+ g_debug("Entry filename output: '%s'", path);
+ FILE *fp = fopen(path, "w");
+ if ( fp ) {
+ gssize start = MAX(0, (CacheState.entry_history_length-max_history));
+ for ( gssize i = start; i < CacheState.entry_history_length; i++){
+ if ( strlen(CacheState.entry_history[i].string) > 0 ){
+ fprintf(fp, "%s\n", CacheState.entry_history[i].string);
+ }
+ }
+ fclose(fp);
+ }
+ g_free(path);
+ }
+}
+
void __create_window(MenuFlags menu_flags) {
+ input_history_initialize();
+
uint32_t selmask = XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL |
XCB_CW_BIT_GRAVITY | XCB_CW_BACKING_STORE |
XCB_CW_EVENT_MASK | XCB_CW_COLORMAP;
@@ -1476,7 +1556,18 @@ void rofi_view_finalize(RofiViewState *state) {
* This function should be called when the input of the entry is changed.
* TODO: Evaluate if this needs to be a 'signal' on textbox?
*/
-static void rofi_view_input_changed() { rofi_view_take_action("inputchange"); }
+static void rofi_view_input_changed() {
+ rofi_view_take_action("inputchange");
+
+ RofiViewState * state = current_active_menu;
+ if ( state ) {
+ if ( CacheState.entry_history[CacheState.entry_history_index].string != NULL) {
+ g_free(CacheState.entry_history[CacheState.entry_history_index].string);
+ }
+ CacheState.entry_history[CacheState.entry_history_index].string = textbox_get_text(state->text);
+ CacheState.entry_history[CacheState.entry_history_index].index = textbox_get_cursor(state->text);
+ }
+}
static void rofi_view_trigger_global_action(KeyBindingAction action) {
RofiViewState *state = rofi_view_get_active();
@@ -1731,6 +1822,44 @@ static void rofi_view_trigger_global_action(KeyBindingAction action) {
state->quit = TRUE;
break;
}
+ case ENTRY_HISTORY_DOWN: {
+ if ( state->text ) {
+ CacheState.entry_history[CacheState.entry_history_index].index = textbox_get_cursor(state->text);
+ if ( CacheState.entry_history_index > 0 ) {
+ CacheState.entry_history_index--;
+ }
+ if ( state->text ) {
+ textbox_text(state->text, CacheState.entry_history[CacheState.entry_history_index].string);
+ textbox_cursor(state->text,CacheState.entry_history[CacheState.entry_history_index].index );
+ state->refilter = TRUE;
+ }
+ }
+ break;
+ }
+ case ENTRY_HISTORY_UP: {
+ if ( state->text ) {
+ if ( CacheState.entry_history[CacheState.entry_history_index].string != NULL) {
+ g_free(CacheState.entry_history[CacheState.entry_history_index].string);
+ }
+ CacheState.entry_history[CacheState.entry_history_index].string = textbox_get_text(state->text);
+ CacheState.entry_history[CacheState.entry_history_index].index = textbox_get_cursor(state->text);
+ // Don't create up if current is empty.
+ if ( strlen(CacheState.entry_history[CacheState.entry_history_index].string) > 0 ) {
+ CacheState.entry_history_index++;
+ if ( CacheState.entry_history_index >= CacheState.entry_history_length ) {
+ CacheState.entry_history = g_realloc(CacheState.entry_history,
+ sizeof(EntryHistoryIndex)*(CacheState.entry_history_length+1));
+ CacheState.entry_history[CacheState.entry_history_length].string = g_strdup("");
+ CacheState.entry_history[CacheState.entry_history_length].index = 0;
+ CacheState.entry_history_length++;
+ }
+ }
+ textbox_text(state->text, CacheState.entry_history[CacheState.entry_history_index].string);
+ textbox_cursor(state->text,CacheState.entry_history[CacheState.entry_history_index].index );
+ state->refilter = TRUE;
+ }
+ break;
+ }
}
}
@@ -2443,6 +2572,8 @@ void rofi_view_cleanup() {
}
xcb_flush(xcb->connection);
g_assert(g_queue_is_empty(&(CacheState.views)));
+
+ input_history_save();
}
void rofi_view_workers_initialize(void) {
TICK_N("Setup Threadpool, start");
diff --git a/source/widgets/textbox.c b/source/widgets/textbox.c
index 6b7030db..95e3f3b9 100644
--- a/source/widgets/textbox.c
+++ b/source/widgets/textbox.c
@@ -359,6 +359,15 @@ void textbox_set_pango_attributes(textbox *tb, PangoAttrList *list) {
pango_layout_set_attributes(tb->layout, list);
}
+char *textbox_get_text ( const textbox *tb ) {
+ if ( tb->text == NULL ) {
+ return g_strdup("");
+ }
+ return g_strdup( tb->text );
+}
+int textbox_get_cursor ( const textbox *tb ) {
+ return tb->cursor;
+}
// set the default text to display
void textbox_text(textbox *tb, const char *text) {
if (tb == NULL) {
diff --git a/test/mode-test.c b/test/mode-test.c
index 67c55fbb..c67c89a8 100644
--- a/test/mode-test.c
+++ b/test/mode-test.c
@@ -127,7 +127,7 @@ END_TEST
START_TEST(test_mode_num_items) {
unsigned int rows = mode_get_num_entries(&help_keys_mode);
- ck_assert_int_eq(rows, 77);
+ ck_assert_int_eq(rows, 79);
for (unsigned int i = 0; i < rows; i++) {
int state = 0;
GList *list = NULL;