diff options
-rw-r--r-- | completions/tofi | 3 | ||||
-rw-r--r-- | doc/config | 5 | ||||
-rw-r--r-- | doc/tofi.5.md | 25 | ||||
-rw-r--r-- | doc/tofi.5.scd | 16 | ||||
-rw-r--r-- | src/config.c | 2 | ||||
-rw-r--r-- | src/history.c | 51 | ||||
-rw-r--r-- | src/history.h | 9 | ||||
-rw-r--r-- | src/main.c | 27 | ||||
-rw-r--r-- | src/tofi.h | 2 |
9 files changed, 117 insertions, 23 deletions
diff --git a/completions/tofi b/completions/tofi index fc8ab90..b766266 100644 --- a/completions/tofi +++ b/completions/tofi @@ -46,6 +46,7 @@ _tofi() --horizontal --hide-cursor --history + --history-file --fuzzy-match --require-match --hide-input @@ -60,6 +61,8 @@ _tofi() case "${prev}" in --font) ;& + --history-file) + ;& --include) ;& --config|-c) @@ -143,6 +143,11 @@ # Sort results by number of usages in run and drun modes. history = true + # Specify an alternate file to read and store history information + # from / to. This shouldn't normally be needed, and is intended to + # facilitate the creation of custom modes. + # history-file = /path/to/histfile + # Use fuzzy matching for searches. fuzzy-match = false diff --git a/doc/tofi.5.md b/doc/tofi.5.md index ff616ff..a534676 100644 --- a/doc/tofi.5.md +++ b/doc/tofi.5.md @@ -40,10 +40,33 @@ options. **history**=*true\|false* -> Sort results by number of usages in run and drun modes. +> Sort results by number of usages. By default, this is only effective +> in the run and drun modes - see the **history-file** option for more +> information. > > Default: true +**history-file**=*path* + +> Specify an alternate file to read and store history information from / +> to. This shouldn't normally be needed, and is intended to facilitate +> the creation of custom modes. The default value depends on the current +> mode. +> +> Defaults: +> +> > > · +> > > +> > > tofi: None (no history file) +> > +> > > · +> > > +> > > tofi-run: *\$XDG_STATE_HOME/tofi-history* +> > +> > > · +> > > +> > > tofi-drun: *\$XDG_STATE_HOME/tofi-drun-history* + **fuzzy-match**=*true\|false* > If true, searching is performed via a simple fuzzy matching algorithm. diff --git a/doc/tofi.5.scd b/doc/tofi.5.scd index f809103..13b8c13 100644 --- a/doc/tofi.5.scd +++ b/doc/tofi.5.scd @@ -39,10 +39,24 @@ options. Default: false *history*=_true|false_ - Sort results by number of usages in run and drun modes. + Sort results by number of usages. By default, this is only effective in + the run and drun modes - see the *history-file* option for more + information. Default: true +*history-file*=_path_ + Specify an alternate file to read and store history information from / + to. This shouldn't normally be needed, and is intended to facilitate + the creation of custom modes. The default value depends on the current + mode. + + Defaults: + - tofi: None (no history file) + - tofi-run: _$XDG_STATE_HOME/tofi-history_ + - tofi-drun: _$XDG_STATE_HOME/tofi-drun-history_ + + *fuzzy-match*=_true|false_ If true, searching is performed via a simple fuzzy matching algorithm. If false, substring matching is used, weighted to favour matches closer diff --git a/src/config.c b/src/config.c index 0875d86..34bc8eb 100644 --- a/src/config.c +++ b/src/config.c @@ -411,6 +411,8 @@ bool parse_option(struct tofi *tofi, const char *filename, size_t lineno, const tofi->hide_cursor = parse_bool(filename, lineno, value, &err); } else if (strcasecmp(option, "history") == 0) { tofi->use_history = parse_bool(filename, lineno, value, &err); + } else if (strcasecmp(option, "history-file") == 0) { + snprintf(tofi->history_file, N_ELEM(tofi->history_file), "%s", value); } else if (strcasecmp(option, "fuzzy-match") == 0) { tofi->fuzzy_match = parse_bool(filename, lineno, value, &err); } else if (strcasecmp(option, "require-match") == 0) { diff --git a/src/history.c b/src/history.c index 95e7760..3bd76fa 100644 --- a/src/history.c +++ b/src/history.c @@ -11,6 +11,8 @@ #include "mkdirp.h" #include "xmalloc.h" +#define MAX_HISTFILE_SIZE (10*1024*1024) + static const char *default_state_dir = ".local/state"; static const char *histfile_basename = "tofi-history"; static const char *drun_histfile_basename = "tofi-drun-history"; @@ -58,16 +60,11 @@ static char *get_histfile_path(bool drun) { return histfile_name; } -struct history history_load(bool drun) +struct history history_load(const char *path) { struct history vec = history_create(); - char *histfile_name = get_histfile_path(drun); - if (histfile_name == NULL) { - return vec; - } - FILE *histfile = fopen(histfile_name, "rb"); - free(histfile_name); + FILE *histfile = fopen(path, "rb"); if (histfile == NULL) { return vec; @@ -82,6 +79,13 @@ struct history history_load(bool drun) errno = 0; size_t len = ftell(histfile); + if (len > MAX_HISTFILE_SIZE) { + log_error("History file too big (> %d MiB)! Are you sure it's a file?\n", MAX_HISTFILE_SIZE / 1024 / 1024); + fclose(histfile); + return vec; + } + + errno = 0; if (fseek(histfile, 0, SEEK_SET) != 0) { log_error("Error seeking in history file: %s.\n", strerror(errno)); fclose(histfile); @@ -115,20 +119,15 @@ struct history history_load(bool drun) return vec; } -void history_save(struct history *history, bool drun) +void history_save(const struct history *history, const char *path) { - char *histfile_name = get_histfile_path(drun); - if (histfile_name == NULL) { - return; - } - /* Create the path if necessary. */ - if (!mkdirp(histfile_name)) { + if (!mkdirp(path)) { return; } /* Use open rather than fopen to ensure the proper permissions. */ - int histfd = open(histfile_name, O_WRONLY | O_CREAT, 0600); + int histfd = open(path, O_WRONLY | O_CREAT, 0600); FILE *histfile = fdopen(histfd, "wb"); if (histfile == NULL) { return; @@ -139,6 +138,28 @@ void history_save(struct history *history, bool drun) } fclose(histfile); +} + +struct history history_load_default_file(bool drun) +{ + char *histfile_name = get_histfile_path(drun); + if (histfile_name == NULL) { + return history_create(); + } + + struct history vec = history_load(histfile_name); + free(histfile_name); + + return vec; +} + +void history_save_default_file(const struct history *history, bool drun) +{ + char *histfile_name = get_histfile_path(drun); + if (histfile_name == NULL) { + return; + } + history_save(history, histfile_name); free(histfile_name); } diff --git a/src/history.h b/src/history.h index 199e028..98e4bd2 100644 --- a/src/history.h +++ b/src/history.h @@ -25,8 +25,13 @@ void history_add(struct history *restrict vec, const char *restrict str); //void history_remove(struct history *restrict vec, const char *restrict str); [[nodiscard("memory leaked")]] -struct history history_load(bool drun); +struct history history_load(const char *path); -void history_save(struct history *history, bool drun); +void history_save(const struct history *history, const char *path); + +[[nodiscard("memory leaked")]] +struct history history_load_default_file(bool drun); + +void history_save_default_file(const struct history *history, bool drun); #endif /* HISTORY_H */ @@ -799,6 +799,7 @@ static void usage() " --hide-cursor <true|false> Hide the cursor.\n" " --horizontal <true|false> List results horizontally.\n" " --history <true|false> Sort results by number of usages.\n" +" --history-file <path> Location of history file.\n" " --fuzzy-match <true|false> Use fuzzy matching for searching.\n" " --require-match <true|false> Require a match for selection.\n" " --hide-input <true|false> Hide sensitive input such as passwords.\n" @@ -857,6 +858,7 @@ const struct option long_options[] = { {"horizontal", required_argument, NULL, 0}, {"hide-cursor", required_argument, NULL, 0}, {"history", required_argument, NULL, 0}, + {"history-file", required_argument, NULL, 0}, {"fuzzy-match", required_argument, NULL, 0}, {"require-match", required_argument, NULL, 0}, {"hide-input", required_argument, NULL, 0}, @@ -980,7 +982,11 @@ static bool do_submit(struct tofi *tofi) history_add( &entry->history, entry->results.buf[selection].string); - history_save(&entry->history, entry->drun); + if (tofi->history_file[0] == 0) { + history_save_default_file(&entry->history, entry->drun); + } else { + history_save(&entry->history, tofi->history_file); + } } return true; } @@ -1297,7 +1303,11 @@ int main(int argc, char *argv[]) log_indent(); tofi.window.entry.commands = compgen_cached(); if (tofi.use_history) { - tofi.window.entry.history = history_load(tofi.window.entry.drun); + if (tofi.history_file[0] == 0) { + tofi.window.entry.history = history_load_default_file(tofi.window.entry.drun); + } else { + tofi.window.entry.history = history_load(tofi.history_file); + } compgen_history_sort(&tofi.window.entry.commands, &tofi.window.entry.history); } log_unindent(); @@ -1308,7 +1318,11 @@ int main(int argc, char *argv[]) tofi.window.entry.drun = true; struct desktop_vec apps = drun_generate_cached(); if (tofi.use_history) { - tofi.window.entry.history = history_load(tofi.window.entry.drun); + if (tofi.history_file[0] == 0) { + tofi.window.entry.history = history_load_default_file(tofi.window.entry.drun); + } else { + tofi.window.entry.history = history_load(tofi.history_file); + } if (tofi.window.entry.drun) { drun_history_sort(&apps, &tofi.window.entry.history); } @@ -1333,7 +1347,12 @@ int main(int argc, char *argv[]) string_vec_add(&tofi.window.entry.commands, line); } free(line); - tofi.use_history = false; + if (tofi.history_file[0] == 0) { + tofi.use_history = false; + } else { + tofi.window.entry.history = history_load(tofi.history_file); + } + compgen_history_sort(&tofi.window.entry.commands, &tofi.window.entry.history); } tofi.window.entry.results = string_vec_copy(&tofi.window.entry.commands); @@ -14,6 +14,7 @@ #define MAX_OUTPUT_NAME_LEN 256 #define MAX_TERMINAL_NAME_LEN 256 +#define MAX_HISTORY_FILE_NAME_LEN 256 struct output_list_element { struct wl_list link; @@ -96,6 +97,7 @@ struct tofi { bool multiple_instance; char target_output_name[MAX_OUTPUT_NAME_LEN]; char default_terminal[MAX_TERMINAL_NAME_LEN]; + char history_file[MAX_HISTORY_FILE_NAME_LEN]; }; #endif /* TOFI_H */ |