31#define G_LOG_DOMAIN "Helper"
43#include <glib/gstdio.h>
45#include <pango/pango-fontmap.h>
46#include <pango/pango.h>
47#include <pango/pangocairo.h>
58 "Normal",
"Regex",
"Glob",
"Fuzzy",
"Prefix"};
71 "on focused monitor",
"on focused window",
"at mouse pointer",
72 "on monitor with focused window",
"on monitor that has mouse pointer"};
103 GError *error = NULL;
105 h = g_hash_table_new(g_str_hash, g_str_equal);
107 g_hash_table_insert(h,
"{terminal}",
config.terminal_emulator);
108 g_hash_table_insert(h,
"{ssh-client}",
config.ssh_client);
111 va_start(ap, length);
113 char *key = va_arg(ap,
char *);
114 if (key == (
char *)0) {
117 char *value = va_arg(ap,
char *);
118 if (value == (
char *)0) {
121 g_hash_table_insert(h, key, value);
127 g_hash_table_destroy(h);
129 if (g_shell_parse_argv(res, length, output, &error)) {
136 char *msg = g_strdup_printf(
"Failed to parse: '%s'\nError: '%s'",
string,
147 for (
size_t i = 0; tokens && tokens[i]; i++) {
148 g_regex_unref((GRegex *)tokens[i]->regex);
155 gchar *r = g_regex_escape_string(input, -1);
156 size_t str_l = strlen(r);
157 for (
size_t i = 0; i < str_l; i++) {
159 if (r[i + 1] ==
'*') {
161 }
else if (r[i + 1] ==
'?') {
171 GString *str = g_string_new(
"");
172 gchar *r = g_regex_escape_string(input, -1);
175 for (iter = r; iter && *iter !=
'\0'; iter = g_utf8_next_char(iter)) {
177 g_string_append(str,
"(");
179 g_string_append(str,
".*?(");
182 g_string_append_c(str,
'\\');
183 iter = g_utf8_next_char(iter);
185 if ((*iter) ==
'\0') {
189 g_string_append_unichar(str, g_utf8_get_char(iter));
190 g_string_append(str,
")");
194 retv = g_string_free(str, FALSE);
199 gchar *r = g_regex_escape_string(input, -1);
200 char *retv = g_strconcat(
"\\b", r, NULL);
212 char *s = g_utf8_normalize(os, -1, G_NORMALIZE_ALL);
213 ssize_t str_size = (g_utf8_strlen(s, -1) * 6 + 2 + 1) *
sizeof(
char);
214 char *str = g_malloc0(str_size);
216 for (
const char *iter = s; iter && *iter; iter = g_utf8_next_char(iter)) {
217 gunichar uc = g_utf8_get_char(iter);
218 if (!g_unichar_ismark(uc)) {
219 int l = g_unichar_to_utf8(uc, buf);
220 memcpy(striter, buf, l);
230static inline GRegex *
R(
const char *s,
int case_sensitive) {
231 if (
config.normalize_match) {
234 GRegex *r = g_regex_new(
235 str, G_REGEX_OPTIMIZE | ((case_sensitive) ? 0 : G_REGEX_CASELESS), 0,
242 s, G_REGEX_OPTIMIZE | ((case_sensitive) ? 0 : G_REGEX_CASELESS), 0, NULL);
249 if (input && input[0] ==
config.matching_negate_char) {
253 switch (
config.matching_method) {
256 retv =
R(r, case_sensitive);
260 retv =
R(input, case_sensitive);
262 r = g_regex_escape_string(input, -1);
263 retv =
R(r, case_sensitive);
269 retv =
R(r, case_sensitive);
274 retv =
R(r, case_sensitive);
278 r = g_regex_escape_string(input, -1);
279 retv =
R(r, case_sensitive);
290 size_t len = strlen(input);
295 char *saveptr = NULL, *token;
307 char *str = g_strdup(input);
311 const char *
const sep =
" ";
312 for (token = strtok_r(str, sep, &saveptr); token != NULL;
313 token = strtok_r(NULL, sep, &saveptr)) {
316 retv[num_tokens + 1] = NULL;
345 const char **retv = NULL;
353 retv = g_malloc0((length + 1) *
sizeof(
char *));
367 if (val != NULL && i > 0 && i < (
stored_argc - 1)) {
376 if (val != NULL && i > 0 && i < (
stored_argc - 1)) {
384 const size_t len = strlen(arg);
390 if (len == 2 && arg[0] ==
'\\') {
423 if (len > 2 && arg[0] ==
'\\' && arg[1] ==
'x') {
424 return (
char)strtol(&arg[2], NULL, 16);
426 g_warning(
"Failed to parse character string: \"%s\"", arg);
434 if (val != NULL && i > 0 && i < (
stored_argc - 1)) {
445 PangoAttribute *pa = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
446 pa->start_index = start;
448 pango_attr_list_insert(retv, pa);
450#if PANGO_VERSION_CHECK(1, 50, 0)
453 pango_attr_text_transform_new(PANGO_TEXT_TRANSFORM_UPPERCASE);
454 pa->start_index = start;
456 pango_attr_list_insert(retv, pa);
460 pango_attr_text_transform_new(PANGO_TEXT_TRANSFORM_LOWERCASE);
461 pa->start_index = start;
463 pango_attr_list_insert(retv, pa);
468 pango_attr_text_transform_new(PANGO_TEXT_TRANSFORM_CAPITALIZE);
469 pa->start_index = start;
471 pango_attr_list_insert(retv, pa);
477 PangoAttribute *pa = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
478 pa->start_index = start;
480 pango_attr_list_insert(retv, pa);
483 PangoAttribute *pa = pango_attr_strikethrough_new(TRUE);
484 pa->start_index = start;
486 pango_attr_list_insert(retv, pa);
489 PangoAttribute *pa = pango_attr_style_new(PANGO_STYLE_ITALIC);
490 pa->start_index = start;
492 pango_attr_list_insert(retv, pa);
495 PangoAttribute *pa = pango_attr_foreground_new(
497 pa->start_index = start;
499 pango_attr_list_insert(retv, pa);
502 pa = pango_attr_foreground_alpha_new(th.
color.
alpha * 65535);
503 pa->start_index = start;
505 pango_attr_list_insert(retv, pa);
513 PangoAttrList *retv) {
515 if (
config.normalize_match) {
520 for (
int j = 0; tokens[j]; j++) {
521 GMatchInfo *gmi = NULL;
522 if (tokens[j]->invert) {
525 g_regex_match(tokens[j]->regex, input, G_REGEX_MATCH_PARTIAL, &gmi);
526 while (g_match_info_matches(gmi)) {
527 int count = g_match_info_get_match_count(gmi);
528 for (
int index = (
count > 1) ? 1 : 0; index <
count; index++) {
530 g_match_info_fetch_pos(gmi, index, &start, &end);
533 g_match_info_next(gmi, NULL);
535 g_match_info_free(gmi);
545 if (
config.normalize_match) {
547 for (
int j = 0; match && tokens[j]; j++) {
548 match = g_regex_match(tokens[j]->regex, r, 0, NULL);
549 match ^= tokens[j]->invert;
553 for (
int j = 0; match && tokens[j]; j++) {
554 match = g_regex_match(tokens[j]->regex, input, 0, NULL);
555 match ^= tokens[j]->invert;
568 GError *error = NULL;
569 g_spawn_async_with_pipes(NULL, args, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
570 NULL, NULL, &fd, NULL, &error);
573 char *msg = g_strdup_printf(
"Failed to execute: '%s'\nError: '%s'", cmd,
590 int fd = g_open(
pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
592 g_warning(
"Failed to create pid file: '%s'.",
pidfile);
596 int flags = fcntl(fd, F_GETFD, NULL);
598 if (fcntl(fd, F_SETFD,
flags, NULL) < 0) {
599 g_warning(
"Failed to set CLOEXEC on pidfile.");
604 int retv = flock(fd, LOCK_EX | LOCK_NB);
606 g_warning(
"Failed to set lock on pidfile: Rofi already running?");
607 g_warning(
"Got error: %d %s", retv, g_strerror(errno));
612 ssize_t l = read(fd, &(buffer[0]), 63);
615 pid_t pid = g_ascii_strtoll(buffer, NULL, 0);
618 retv = flock(fd, LOCK_EX | LOCK_NB);
632 if (ftruncate(fd, (off_t)0) == 0) {
635 int length = snprintf(buffer, 64,
"%i", getpid());
638 l += write(fd, &buffer[l], length - l);
647 g_warning(
"Failed to close pidfile: '%s'", g_strerror(errno));
653 const char *fam = pango_font_description_get_family(pfd);
654 int size = pango_font_description_get_size(pfd);
655 if (fam == NULL || size == 0) {
656 g_debug(
"Pango failed to parse font: '%s'", font);
657 g_debug(
"Got family: <b>%s</b> at size: <b>%d</b>", fam ? fam :
"{unknown}",
672 int found_error = FALSE;
674 g_string_new(
"<big><b>The configuration failed to validate:</b></big>\n");
676 if (
config.sorting_method) {
677 if (g_strcmp0(
config.sorting_method,
"normal") == 0) {
679 }
else if (g_strcmp0(
config.sorting_method,
"levenshtein") == 0) {
681 }
else if (g_strcmp0(
config.sorting_method,
"fzf") == 0) {
683 }
else if (g_strcmp0(
config.sorting_method,
"fzf-v2") == 0) {
686 g_string_append_printf(
688 "\t<b>config.sorting_method</b>=%s is not a valid sorting "
689 "strategy.\nValid options are: normal, fzf or fzf-v2.\n",
696 char **strv = g_strsplit(
config.matching,
",", 0);
698 int matching_method_index = 0;
699 for (
char **str = strv; *str && matching_method_index <
MM_NUM_MATCHERS;
701 gboolean found = FALSE;
707 matching_method_index++;
711 g_string_append_printf(msg,
712 "\t<b>config.matching</b> = %s to many "
713 "matching options enabled.\n",
720 g_string_append_printf(msg,
721 "\t<b>config.matching</b>=%s is not a valid "
722 "matching strategy.\nValid options are: glob, "
723 "regex, fuzzy, prefix or normal.\n",
733 if (
config.element_height < 1) {
734 g_string_append_printf(msg,
735 "\t<b>config.element_height</b>=%d is invalid. An "
736 "element needs to be at least 1 line high.\n",
738 config.element_height = 1;
742 g_string_append_printf(msg,
743 "\t<b>config.location</b>=%d is invalid. Value "
744 "should be between %d and %d.\n",
755 const char *name =
config.monitor;
756 if (name && name[0] ==
'-') {
757 int index = name[1] -
'0';
758 if (index < 5 && index > 0) {
762 g_string_append_printf(
763 msg,
"\t<b>config.monitor</b>=%s Could not find monitor.\n", name);
769 if (g_strcmp0(
config.monitor,
"-3") == 0) {
775 g_string_append(msg,
"Please update your configuration.");
780 g_string_free(msg, TRUE);
788 char **str = g_strsplit(input, G_DIR_SEPARATOR_S, -1);
789 for (
unsigned int i = 0; str && str[i]; i++) {
791 if (str[i][0] ==
'~' && str[i][1] ==
'\0') {
793 str[i] = g_strdup(g_get_home_dir());
796 else if (str[i][0] ==
'~') {
797 struct passwd *p = getpwnam(&(str[i][1]));
800 str[i] = g_strdup(p->pw_dir);
804 if (input[0] == G_DIR_SEPARATOR) {
805 str[i] = g_strdup_printf(
"%s%s", G_DIR_SEPARATOR_S, s);
810 char *retv = g_build_filenamev(str);
816#define MIN3(a, b, c) \
817 ((a) < (b) ? ((a) < (c) ? (a) : (c)) : ((b) < (c) ? (b) : (c)))
819unsigned int levenshtein(
const char *needle,
const glong needlelen,
820 const char *haystack,
const glong haystacklen,
821 int case_sensitive) {
822 if (needlelen == G_MAXLONG) {
826 unsigned int column[needlelen + 1];
827 for (glong y = 0; y < needlelen; y++) {
832 column[needlelen] = needlelen;
833 for (glong x = 1; x <= haystacklen; x++) {
834 const char *needles = needle;
836 gunichar haystackc = g_utf8_get_char(haystack);
837 if (!case_sensitive) {
838 haystackc = g_unichar_tolower(haystackc);
840 for (glong y = 1, lastdiag = x - 1; y <= needlelen; y++) {
841 gunichar needlec = g_utf8_get_char(needles);
842 if (!case_sensitive) {
843 needlec = g_unichar_tolower(needlec);
845 unsigned int olddiag = column[y];
846 column[y] =
MIN3(column[y] + 1, column[y - 1] + 1,
847 lastdiag + (needlec == haystackc ? 0 : 1));
849 needles = g_utf8_next_char(needles);
851 haystack = g_utf8_next_char(haystack);
853 return column[needlelen];
858 return g_convert_with_fallback(input, length,
"UTF-8",
"latin1",
"\uFFFD",
859 NULL, &slength, NULL);
867 length = strlen(data);
872 if (g_utf8_validate(data, length, &end)) {
873 return g_strndup(data, length);
875 string = g_string_sized_new(length + 16);
879 g_string_append_len(
string, data, end - data);
881 g_string_append(
string,
"\uFFFD");
882 length -= (end - data) + 1;
884 }
while (!g_utf8_validate(data, length, &end));
887 g_string_append_len(
string, data, length);
890 return g_string_free(
string, FALSE);
898#define FUZZY_SCORER_MAX_LENGTH 256
900#define MIN_SCORE (INT_MIN / 2)
902#define LEADING_GAP_SCORE -4
906#define WORD_START_SCORE 50
908#define NON_WORD_SCORE 40
910#define CAMEL_SCORE (WORD_START_SCORE + GAP_SCORE - 1)
912#define CONSECUTIVE_SCORE (WORD_START_SCORE + GAP_SCORE)
914#define PATTERN_NON_START_MULTIPLIER 1
916#define PATTERN_START_MULTIPLIER 2
938 if (g_unichar_islower(c)) {
941 if (g_unichar_isupper(c)) {
944 if (g_unichar_isdigit(c)) {
972 glong slen,
int case_sensitive) {
978 gboolean pfirst = TRUE;
980 gboolean pstart = TRUE;
982 int *score = g_malloc_n(slen,
sizeof(
int));
984 int *dp = g_malloc_n(slen,
sizeof(
int));
987 int uleft = 0, ulefts = 0, left, lefts;
988 const gchar *pit = pattern, *sit;
990 for (si = 0, sit = str; si < slen; si++, sit = g_utf8_next_char(sit)) {
996 for (pi = 0; pi < plen; pi++, pit = g_utf8_next_char(pit)) {
997 gunichar pc = g_utf8_get_char(pit), sc;
998 if (g_unichar_isspace(pc)) {
1003 for (si = 0, sit = str; si < slen; si++, sit = g_utf8_next_char(sit)) {
1006 sc = g_utf8_get_char(sit);
1007 if (case_sensitive ? pc == sc
1008 : g_unichar_tolower(pc) == g_unichar_tolower(sc)) {
1019 pfirst = pstart = FALSE;
1022 for (si = 0; si < slen; si++) {
1054#define FZF_V2_SCORE_MATCH 16
1056#define FZF_V2_SCORE_GAP_START (-3)
1058#define FZF_V2_SCORE_GAP_EXTENSION (-1)
1060#define FZF_V2_BONUS_BOUNDARY 8
1062#define FZF_V2_BONUS_NON_WORD 8
1064#define FZF_V2_BONUS_CAMEL_123 \
1065 (FZF_V2_BONUS_BOUNDARY + FZF_V2_SCORE_GAP_EXTENSION)
1067#define FZF_V2_BONUS_CONSECUTIVE \
1068 (-(FZF_V2_SCORE_GAP_START + FZF_V2_SCORE_GAP_EXTENSION))
1070#define FZF_V2_BONUS_FIRST_CHAR_MULTIPLIER 2
1072#define FZF_V2_BONUS_BOUNDARY_WHITE (FZF_V2_BONUS_BOUNDARY + 2)
1074#define FZF_V2_BONUS_BOUNDARY_DELIMITER (FZF_V2_BONUS_BOUNDARY + 1)
1076#define FZF_V2_MIN_SCORE (G_MININT / 2)
1090 if (g_unichar_islower(c)) {
1093 if (g_unichar_isupper(c)) {
1096 if (g_unichar_isdigit(c)) {
1099 if (g_unichar_isalpha(c)) {
1102 if (g_unichar_isspace(c)) {
1106 if (c < 0x80 && strchr(
"/,:;|", (
char)c) != NULL) {
1157 const gunichar *tmatch,
const int *B,
1158 glong N,
int case_sensitive) {
1167 int *H = g_malloc0_n((gsize)M * N,
sizeof(
int));
1168 int *C = g_malloc0_n((gsize)M * N,
sizeof(
int));
1169 glong *F = g_malloc_n(M,
sizeof(glong));
1171 gunichar pchar0 = case_sensitive ? pat[0] : g_unichar_tolower(pat[0]);
1176 gboolean in_gap = FALSE;
1177 glong pidx = 0, last_idx = 0;
1178 gunichar pchar_adv = pchar0;
1180 for (glong off = 0; off < N; off++) {
1181 if (tmatch[off] == pchar_adv) {
1188 pchar_adv = case_sensitive ? pat[MIN(pidx, M - 1)]
1189 : g_unichar_tolower(pat[MIN(pidx, M - 1)]);
1194 if (tmatch[off] == pchar0) {
1199 if (M == 1 && sc > max_score) {
1219 }
else if (M == 1) {
1224 for (glong i = 1; i < M; i++) {
1225 gunichar pchar = case_sensitive ? pat[i] : g_unichar_tolower(pat[i]);
1228 int *row = H + i * N;
1229 int *crow = C + i * N;
1230 int *diag = H + (i - 1) * N;
1231 int *cdiag = C + (i - 1) * N;
1232 for (glong j = f; j <= last_idx; j++) {
1233 int s1 = 0, s2, consecutive = 0;
1234 int hleft = (j > f) ? row[j - 1] : 0;
1237 if (pchar == tmatch[j]) {
1240 consecutive = cdiag[j - 1] + 1;
1241 if (consecutive > 1) {
1242 int fb = B[j - consecutive + 1];
1256 crow[j] = consecutive;
1258 int sc = MAX(MAX(s1, s2), 0);
1259 if (i == M - 1 && sc > max_score) {
1275 const char *str, glong slen,
1276 int case_sensitive) {
1289 char *npattern = NULL, *nstr = NULL;
1290 if (
config.normalize_match) {
1298 gunichar *txt = g_utf8_to_ucs4_fast(str, -1, &N);
1304 gunichar *tmatch = g_malloc_n(N,
sizeof(gunichar));
1305 int *B = g_malloc_n(N,
sizeof(
int));
1307 for (glong off = 0; off < N; off++) {
1309 tmatch[off] = case_sensitive ? txt[off] : g_unichar_tolower(txt[off]);
1317 gboolean any_term = FALSE;
1318 gchar **terms = g_strsplit_set(pattern,
" \t\n\r\v\f", -1);
1319 for (gchar **t = terms; *t != NULL; t++) {
1320 if ((*t)[0] ==
'\0') {
1325 gunichar *pat = g_utf8_to_ucs4_fast(*t, -1, &tm);
1336 int result = any_term ? total : 0;
1348 if (val > G_MAXUINT16) {
1354 return (guint16)val;
1359 const char *first = str;
1360 while (*first !=
'\0' && g_unichar_isspace(g_utf8_get_char(first))) {
1361 first = g_utf8_next_char(first);
1363 const char *last = first + strlen(first);
1364 while (last > first) {
1365 const char *prev = g_utf8_prev_char(last);
1366 if (!g_unichar_isspace(g_utf8_get_char(prev))) {
1387 return (
int)((by_score << 15) | by_length);
1402 char *na = g_utf8_normalize(a, -1, G_NORMALIZE_ALL_COMPOSE);
1403 char *nb = g_utf8_normalize(b, -1, G_NORMALIZE_ALL_COMPOSE);
1404 if (na == NULL && nb == NULL)
1414 size_t la = MIN(n, (
size_t)g_utf8_strlen(na, -1));
1415 size_t lb = MIN(n, (
size_t)g_utf8_strlen(nb, -1));
1416 *g_utf8_offset_to_pointer(na, la) =
'\0';
1417 *g_utf8_offset_to_pointer(nb, lb) =
'\0';
1418 int r = g_utf8_collate(na, nb);
1425 const char *error_cmd,
1430 const char *error_precmd,
const char *error_cmd,
1432 gboolean retv = TRUE;
1433 GError *error = NULL;
1435 GSpawnChildSetupFunc child_setup = NULL;
1436 gpointer user_data = NULL;
1440 g_spawn_async(wd, args, envp, G_SPAWN_SEARCH_PATH, child_setup, user_data,
1442 if (error != NULL) {
1443 char *msg = g_strdup_printf(
"Failed to execute: '%s%s'\nError: '%s'",
1444 error_precmd, error_cmd, error->message);
1448 g_error_free(error);
1458 gboolean run_in_term,
1464 gboolean run_in_term,
1482 if (context != NULL) {
1483 if (context->
name == NULL) {
1484 context->
name = args[0];
1486 if (context->
binary == NULL) {
1487 context->
binary = args[0];
1490 gsize l = strlen(
"Launching '' via rofi") + strlen(cmd) + 1;
1491 gchar *description = g_newa(gchar, l);
1493 g_snprintf(description, l,
"Launching '%s' via rofi", cmd);
1496 if (context->
command == NULL) {
1505 const char *parent_file) {
1508 if (g_path_is_absolute(filename)) {
1509 g_debug(
"Opening theme, path is absolute: %s", filename);
1510 if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
1511 return g_strdup(filename);
1513 g_debug(
"Opening theme, path is absolute but does not exists: %s",
1516 if (parent_file != NULL) {
1518 char *basedir = g_path_get_dirname(parent_file);
1519 char *path = g_build_filename(basedir, filename, NULL);
1521 g_debug(
"Opening theme, check in dir where file is included: %s", path);
1522 if (g_file_test(path, G_FILE_TEST_EXISTS)) {
1525 g_debug(
"Opening theme, file does not exists in dir where file is "
1531 const char *cpath = g_get_user_config_dir();
1533 char *themep = g_build_filename(cpath,
"rofi",
"themes", filename, NULL);
1534 g_debug(
"Opening theme, testing: %s", themep);
1535 if (themep && g_file_test(themep, G_FILE_TEST_EXISTS)) {
1542 char *themep = g_build_filename(cpath,
"rofi", filename, NULL);
1543 g_debug(
"Opening theme, testing: %s", themep);
1544 if (g_file_test(themep, G_FILE_TEST_EXISTS)) {
1549 const char *datadir = g_get_user_data_dir();
1552 g_build_filename(datadir,
"rofi",
"themes", filename, NULL);
1554 g_debug(
"Opening theme, testing: %s", theme_path);
1555 if (g_file_test(theme_path, G_FILE_TEST_EXISTS)) {
1562 const gchar *
const *system_data_dirs = g_get_system_data_dirs();
1563 if (system_data_dirs) {
1564 for (uint_fast32_t i = 0; system_data_dirs[i] != NULL; i++) {
1565 const char *
const sdatadir = system_data_dirs[i];
1566 g_debug(
"Opening theme directory: %s", sdatadir);
1568 g_build_filename(sdatadir,
"rofi",
"themes", filename, NULL);
1570 g_debug(
"Opening theme, testing: %s", theme_path);
1571 if (g_file_test(theme_path, G_FILE_TEST_EXISTS)) {
1579 char *theme_path = g_build_filename(THEME_DIR, filename, NULL);
1581 g_debug(
"Opening theme, testing: %s", theme_path);
1582 if (g_file_test(theme_path, G_FILE_TEST_EXISTS)) {
1591 const char *parent_file) {
1594 g_debug(
"Opening theme, testing: %s\n", filename);
1595 if (g_path_is_absolute(filename)) {
1596 g_debug(
"Opening theme, path is absolute: %s", filename);
1597 if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
1601 gboolean ext_found = FALSE;
1602 for (
const char **i = ext; *i != NULL; i++) {
1603 if (g_str_has_suffix(file, *i)) {
1617 g_assert_nonnull(ext[0]);
1619 char *temp = filename;
1620 for (
const char **i = ext; *i != NULL; i++) {
1621 filename = g_strconcat(temp, *i, NULL);
1637 while (input != NULL && isblank(*input)) {
1641 if (input == NULL) {
1645 const char *sep[] = {
"-",
":"};
1646 int pythonic = (strchr(input,
':') || input[0] ==
'-') ? 1 : 0;
1649 for (
char *token = strsep(&input, sep[pythonic]); token != NULL;
1650 token = strsep(&input, sep[pythonic])) {
1652 item->
start = item->
stop = (int)strtol(token, NULL, 10);
1657 if (token[0] ==
'\0') {
1662 item->
stop = (int)strtol(token, NULL, 10);
1671 if (input == NULL) {
1674 const char *
const sep =
",";
1675 for (
char *token = strtok_r(input, sep, &endp); token != NULL;
1676 token = strtok_r(NULL, sep, &endp)) {
1681 if (
parse_pair(token, &((*list)[*length]))) {
1688 int case_sensitive =
config.case_sensitive;
1692 case_sensitive = FALSE;
1694 if (g_utf8_validate(input, -1, &end)) {
1695 for (
const char *c = (input); !case_sensitive && c != NULL && *c;
1696 c = g_utf8_next_char(c)) {
1697 gunichar uc = g_utf8_get_char(c);
1698 if (g_unichar_isupper(uc)) {
1699 case_sensitive = TRUE;
1705 return case_sensitive;
1709 int selected_line,
const char *filter) {
1710 for (
int i = 0; format && format[i]; i++) {
1711 if (format[i] ==
'i') {
1712 fprintf(stdout,
"%d", selected_line);
1713 }
else if (format[i] ==
'd') {
1714 fprintf(stdout,
"%d", (selected_line + 1));
1715 }
else if (format[i] ==
's') {
1716 fputs(
string, stdout);
1717 }
else if (format[i] ==
'p') {
1719 pango_parse_markup(
string, -1, 0, NULL, &esc, NULL, NULL);
1724 fputs(
"invalid string", stdout);
1726 }
else if (format[i] ==
'q') {
1727 char *quote = g_shell_quote(
string);
1728 fputs(quote, stdout);
1730 }
else if (format[i] ==
'f') {
1732 fputs(filter, stdout);
1734 }
else if (format[i] ==
'F') {
1736 char *quote = g_shell_quote(filter);
1737 fputs(quote, stdout);
1741 fputc(format[i], stdout);
1744 fputc(
'\n', stdout);
1752 int num_match = g_match_info_get_match_count(info);
1754 if (num_match == 5) {
1755 match = g_match_info_fetch(info, 4);
1756 if (match != NULL) {
1758 gchar *r = g_hash_table_lookup((GHashTable *)data, match);
1761 g_string_append(res, r);
1768 else if (num_match == 4) {
1769 match = g_match_info_fetch(info, 2);
1770 if (match != NULL) {
1772 gchar *r = g_hash_table_lookup((GHashTable *)data, match);
1775 gchar *prefix = g_match_info_fetch(info, 1);
1776 g_string_append(res, prefix);
1779 g_string_append(res, r);
1781 gchar *post = g_match_info_fetch(info, 3);
1782 g_string_append(res, post);
1796 h = g_hash_table_new(g_str_hash, g_str_equal);
1798 va_start(ap,
string);
1801 char *key = va_arg(ap,
char *);
1802 if (key == (
char *)0) {
1805 char *value = va_arg(ap,
char *);
1806 g_hash_table_insert(h, key, value);
1811 g_hash_table_destroy(h);
1830 GError *error = NULL;
1834 GRegex *reg = g_regex_new(
"\\[(.*)({[-\\w]+})(.*)\\]|({[\\w-]+})",
1835 G_REGEX_UNGREEDY, 0, &error);
1836 if (error == NULL) {
1838 g_regex_replace_eval(reg,
string, -1, 0, 0,
helper_eval_cb2, h, &error);
1843 if (error != NULL) {
1844 char *msg = g_strdup_printf(
"Failed to parse: '%s'\nError: '%s'",
string,
1849 g_error_free(error);
int monitor_active(workarea *mon)
void display_startup_notification(RofiHelperExecuteContext *context, GSpawnChildSetupFunc *child_setup, gpointer *user_data)
struct _workarea workarea
void helper_token_match_set_pango_attr_on_style(PangoAttrList *retv, int start, int end, RofiHighlightColorStyle th)
PangoAttrList * helper_token_match_get_pango_attr(RofiHighlightColorStyle th, rofi_int_matcher **tokens, const char *input, PangoAttrList *retv)
gboolean helper_validate_font(PangoFontDescription *pfd, const char *font)
char * rofi_latin_to_utf8_strdup(const char *input, gssize length)
gboolean helper_execute_command_env(const char *wd, const char *cmd, gboolean run_in_term, RofiHelperExecuteContext *context, char **envp)
void parse_ranges(char *input, rofi_range_pair **list, unsigned int *length)
void cmd_set_arguments(int argc, char **argv)
rofi_int_matcher ** helper_tokenize(const char *input, int case_sensitive)
unsigned int levenshtein(const char *needle, const glong needlelen, const char *haystack, const glong haystacklen, int case_sensitive)
int find_arg_char(const char *const key, char *val)
gboolean helper_execute_env(const char *wd, char **args, const char *error_precmd, const char *error_cmd, RofiHelperExecuteContext *context, gchar **envp)
gboolean helper_execute_command(const char *wd, const char *cmd, gboolean run_in_term, RofiHelperExecuteContext *context)
void helper_select_next_matching_mode(void)
void helper_tokenize_free(rofi_int_matcher **tokens)
char helper_parse_char(const char *arg)
void rofi_output_formatted_line(const char *format, const char *string, int selected_line, const char *filter)
const char * helper_get_matching_mode_str(void)
gboolean helper_execute(const char *wd, char **args, const char *error_precmd, const char *error_cmd, RofiHelperExecuteContext *context)
int rofi_scorer_fzf_v2_evaluate(const char *pattern, glong plen, const char *str, glong slen, int case_sensitive)
char * helper_string_replace_if_exists(char *string,...)
const char ** find_arg_strv(const char *const key)
int helper_parse_setup(char *string, char ***output, int *length,...)
int execute_generator(const char *cmd)
void helper_select_previous_matching_mode(void)
int rofi_scorer_fzf_v2_sort_key(int score, const char *str)
int find_arg_int(const char *const key, int *val)
char * rofi_expand_path(const char *input)
void remove_pid_file(int fd)
int find_arg_str(const char *const key, char **val)
int parse_case_sensitivity(const char *input)
int rofi_scorer_fuzzy_evaluate(const char *pattern, glong plen, const char *str, glong slen, int case_sensitive)
int find_arg_uint(const char *const key, unsigned int *val)
int find_arg(const char *const key)
int helper_token_match(rofi_int_matcher *const *tokens, const char *input)
int create_pid_file(const char *pidfile, gboolean kill_running)
int config_sanity_check(void)
char * rofi_force_utf8(const gchar *data, ssize_t length)
void rofi_add_error_message(GString *str)
int rofi_view_error_dialog(const char *msg, int markup)
#define FZF_V2_BONUS_NON_WORD
static int rofi_scorer_fzf_v2_term(const gunichar *pat, glong M, const gunichar *tmatch, const int *B, glong N, int case_sensitive)
static enum FzfV2CharClass rofi_scorer_fzf_v2_char_class(gunichar c)
#define CONSECUTIVE_SCORE
static guint16 rofi_scorer_fzf_v2_trim_length(const char *str)
#define LEADING_GAP_SCORE
static gchar * prefix_regex(const char *input)
static int MatchingMethodEnabled[MM_NUM_MATCHERS]
static char * utf8_helper_simplify_string(const char *os)
#define FZF_V2_BONUS_CAMEL_123
static gchar * glob_to_regex(const char *input)
const char *const monitor_position_entries[]
#define FZF_V2_SCORE_MATCH
static enum CharClass rofi_scorer_get_character_class(gunichar c)
int utf8_strncmp(const char *a, const char *b, size_t n)
#define FZF_V2_BONUS_FIRST_CHAR_MULTIPLIER
#define PATTERN_NON_START_MULTIPLIER
#define FZF_V2_BONUS_BOUNDARY
#define FZF_V2_BONUS_BOUNDARY_DELIMITER
char * helper_string_replace_if_exists_v(char *string, GHashTable *h)
static int rofi_scorer_fzf_v2_bonus_for(enum FzfV2CharClass prev, enum FzfV2CharClass cur)
#define FZF_V2_SCORE_GAP_EXTENSION
static int NUMMatchingMethodEnabled
static char * helper_get_theme_path_check_file(const char *filename, const char *parent_file)
static int CurrentMatchingMethod
#define FZF_V2_BONUS_BOUNDARY_WHITE
#define FUZZY_SCORER_MAX_LENGTH
static gboolean helper_eval_cb2(const GMatchInfo *info, GString *res, gpointer data)
static guint16 rofi_scorer_fzf_v2_as_uint16(int val)
#define PATTERN_START_MULTIPLIER
char * helper_get_theme_path(const char *file, const char **ext, const char *parent_file)
#define FZF_V2_BONUS_CONSECUTIVE
static rofi_int_matcher * create_regex(const char *input, int case_sensitive)
static GRegex * R(const char *s, int case_sensitive)
#define FZF_V2_SCORE_GAP_START
static gchar * fuzzy_to_regex(const char *input)
const char *const MatchingMethodStr[MM_NUM_MATCHERS]
static gboolean parse_pair(char *input, rofi_range_pair *item)
static int rofi_scorer_get_score_for(enum CharClass prev, enum CharClass curr)
struct rofi_int_matcher_t rofi_int_matcher
const gchar * description