-
Notifications
You must be signed in to change notification settings - Fork 614
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[REQUEST] Prefix sorting #1983
Comments
What exactly do you mean with 'prefix' sorting? sort it alpha numeric on the full string? so it starts with Something like: diff --git a/include/settings.h b/include/settings.h
index 1af9b952..6a803441 100644
--- a/include/settings.h
+++ b/include/settings.h
@@ -46,7 +46,7 @@ typedef enum {
/**
* Possible sorting methods for listview.
*/
-typedef enum { SORT_NORMAL = 0, SORT_FZF = 1 } SortingMethod;
+typedef enum { SORT_NORMAL = 0, SORT_FZF = 1, SORT_ALNUM = 2 } SortingMethod;
/**
* Settings structure holding all (static) configurable options.
diff --git a/source/helper.c b/source/helper.c
index 53f366bf..0777cbde 100644
--- a/source/helper.c
+++ b/source/helper.c
@@ -653,6 +653,8 @@ int config_sanity_check(void) {
config.sorting_method_enum = SORT_NORMAL;
} else if (g_strcmp0(config.sorting_method, "fzf") == 0) {
config.sorting_method_enum = SORT_FZF;
+ } else if (g_strcmp0(config.sorting_method, "alnum") == 0) {
+ config.sorting_method_enum = SORT_ALNUM;
} else {
g_string_append_printf(
msg,
diff --git a/source/view.c b/source/view.c
index aac8c22e..a942f082 100644
--- a/source/view.c
+++ b/source/view.c
@@ -211,6 +211,28 @@ static int lev_sort(const void *p1, const void *p2, void *arg) {
return distances[*a] - distances[*b];
}
+static int alnum_sort(const void *p1, const void *p2, void *arg) {
+ const int *a = p1;
+ const int *b = p2;
+ RofiViewState *state = arg;
+
+ char *str_a = mode_get_completion(state->sw, *a);
+ char *str_b = mode_get_completion(state->sw, *b);
+
+ if (str_a == NULL && str_b == NULL) {
+ return 0;
+ } else if (str_a != NULL && str_b == NULL) {
+ g_free(str_a);
+ return -1;
+ } else if (str_a == NULL && str_b != NULL) {
+ g_free(str_b);
+ return -1;
+ }
+ int retv = g_utf8_collate(str_a, str_b);
+ g_free(str_a);
+ g_free(str_b);
+ return retv;
+}
/**
* Stores a screenshot of Rofi at that point in time.
@@ -765,6 +787,9 @@ static void filter_elements(thread_state *ts,
t->state->distance[i] =
rofi_scorer_fuzzy_evaluate(t->pattern, t->plen, str, slen);
break;
+ case SORT_ALNUM:
+ t->state->distance[i] = 0;
+ break;
case SORT_NORMAL:
default:
t->state->distance[i] = levenshtein(t->pattern, t->plen, str, slen);
@@ -1486,8 +1511,12 @@ static gboolean rofi_view_refilter_real(RofiViewState *state) {
j += states[i].count;
}
if (config.sort) {
- g_qsort_with_data(state->line_map, j, sizeof(int), lev_sort,
- state->distance);
+ if (config.sorting_method_enum == SORT_ALNUM) {
+ g_qsort_with_data(state->line_map, j, sizeof(int), alnum_sort, state);
+ } else {
+ g_qsort_with_data(state->line_map, j, sizeof(int), lev_sort,
+ state->distance);
+ }
}
// Cleanup + bookkeeping.
|
It's a partial improvement, as it put more weight on smaller names. So from my experiments, it can both move them forward if they are small, but backward if the name is long. |
Do you know of a weighting algorithm that does what you want? |
I don't know if there is any algorithm that do that directly, but probably that a custom comparator could do it quite easily. I'm not used to C, but I could try to write an example if you want, maybe in a higher level language. |
Yeah, a high level algo would be useful.. In my experience it sounds easier then it is, for us (knowing what we are looking for ) it sounds obvious, but it often isn't to implement. With the current information, I don't know what would fit your requirements. Currently rofi works with 'distances', the lower the distance the higher it is in the list. |
No problem, converting words and ideas into code is indeed not an easy task. If I stick to a high level language such as python, I would write this kind of comparator function, with As we can see, it's not so much a new algorithm, but rather a "shortcut" for the case where an entry starts with the input. def compare(a: str, b: str, input: str):
if a.startswith(input) and not b.startswith(input):
return 1
elif b.startswith(input) and not a.startswith(input):
return -1
else:
return distance(a, b, index) |
This would most likely favour shorter words just like the fzf algorithm. |
diff --git a/include/settings.h b/include/settings.h
index 1af9b952..6a803441 100644
--- a/include/settings.h
+++ b/include/settings.h
@@ -46,7 +46,7 @@ typedef enum {
/**
* Possible sorting methods for listview.
*/
-typedef enum { SORT_NORMAL = 0, SORT_FZF = 1 } SortingMethod;
+typedef enum { SORT_NORMAL = 0, SORT_FZF = 1, SORT_ALNUM = 2 } SortingMethod;
/**
* Settings structure holding all (static) configurable options.
diff --git a/source/helper.c b/source/helper.c
index 53f366bf..0777cbde 100644
--- a/source/helper.c
+++ b/source/helper.c
@@ -653,6 +653,8 @@ int config_sanity_check(void) {
config.sorting_method_enum = SORT_NORMAL;
} else if (g_strcmp0(config.sorting_method, "fzf") == 0) {
config.sorting_method_enum = SORT_FZF;
+ } else if (g_strcmp0(config.sorting_method, "alnum") == 0) {
+ config.sorting_method_enum = SORT_ALNUM;
} else {
g_string_append_printf(
msg,
diff --git a/source/view.c b/source/view.c
index aac8c22e..c611e3fe 100644
--- a/source/view.c
+++ b/source/view.c
@@ -211,6 +211,38 @@ static int lev_sort(const void *p1, const void *p2, void *arg) {
return distances[*a] - distances[*b];
}
+static int alnum_sort(const void *p1, const void *p2, void *arg) {
+ const int *a = p1;
+ const int *b = p2;
+ RofiViewState *state = arg;
+ int *distances = state->distance;
+
+ char *str_a = mode_get_completion(state->sw, *a);
+ char *str_b = mode_get_completion(state->sw, *b);
+
+ if (str_a == NULL && str_b == NULL) {
+ return 0;
+ } else if (str_a != NULL && str_b == NULL) {
+ g_free(str_a);
+ return -1;
+ } else if (str_a == NULL && str_b != NULL) {
+ g_free(str_b);
+ return -1;
+ }
+
+ char *str = state->text->text;
+ size_t l = strlen(str);
+ if (strncasecmp(str_a, str, l) == 0 && strncasecmp(str_b, str, l) != 0) {
+ return -1;
+ } else if (strncasecmp(str_b, str, l) == 0 &&
+ strncasecmp(str_a, str, l) != 0) {
+ return 1;
+ }
+ int retv = distances[*a] - distances[*b];
+ g_free(str_a);
+ g_free(str_b);
+ return retv;
+}
/**
* Stores a screenshot of Rofi at that point in time.
@@ -765,9 +797,13 @@ static void filter_elements(thread_state *ts,
t->state->distance[i] =
rofi_scorer_fuzzy_evaluate(t->pattern, t->plen, str, slen);
break;
+ case SORT_ALNUM:
+ t->state->distance[i] = levenshtein(t->pattern, t->plen, str, slen);
+ break;
case SORT_NORMAL:
default:
t->state->distance[i] = levenshtein(t->pattern, t->plen, str, slen);
+ printf("%d %s\n", t->state->distance[i], str);
break;
}
g_free(str);
@@ -1486,8 +1522,12 @@ static gboolean rofi_view_refilter_real(RofiViewState *state) {
j += states[i].count;
}
if (config.sort) {
- g_qsort_with_data(state->line_map, j, sizeof(int), lev_sort,
- state->distance);
+ if (config.sorting_method_enum == SORT_ALNUM) {
+ g_qsort_with_data(state->line_map, j, sizeof(int), alnum_sort, state);
+ } else {
+ g_qsort_with_data(state->line_map, j, sizeof(int), lev_sort,
+ state->distance);
+ }
}
// Cleanup + bookkeeping.
``` |
I tried your patch, but wasn't able to see any difference when using In this example, I would except Thunderbird to be ranked way higher than it actually is, as it starts with the user input. |
Pass |
Ok, feel a bit stupid now 😅 Thank you a lot, that was exactly what I was looking for! Any plan to merge this into rofi itself? |
I need to see how to do this utf-8 safe, but I don't see a reason to not merge it. |
@DaveDavenport should you guys use fussy search ? i have same problem with querying items in rofi |
@MirS0bhan what do you mean? can you explain? |
i mean your search algorithm is not good enough and it doesn't show me most related things. and you should use this [https://en.wikipedia.org/wiki/Approximate_string_matching](uzzy string searching) if you already not do it. and also it could make it more efficient if that program aim to count how many times i open my programs or even at which time i open it and it consider it to show the result of search |
@MirS0bhan please continue this on the discussion forum, instead of highjacking this issue (see guidelines). Both things you mention are already available in rofi. |
Before opening a feature request
What is the user problem or growth opportunity you want to see solved?
When looking for an application, we usually search with it prefix. By example, when searching "O", "Onlyoffice" should be shown before "firefox". Thanks to #1237, it's possible to match by prefix. But sometimes, we also search with another word. One good example is "DB Browser for SQLite". It would be nice to be able to sort by prefix, rather than match by it. That way, both uses cases works, and the arguments used in #1237 are still true.
How do you know that this problem exists today? Why is this important?
I'm using rofi many times a day, and while it's awesome, there is sometimes too much friction, when there is a lot of applications.
Who will benefit from it?
Probably everybody, as it's a very common use case to start with the prefix.
Rofi version (rofi -v)
1.7.5+wayland3
Configuration
https://gist.github.com/BhasherBEL/674b236b9ae37a5734378b12b7fcdd62
Additional information
No response
The text was updated successfully, but these errors were encountered: