diff options
Diffstat (limited to 'dotfiles/system/.zsh/modules/Src/aloxaf/fzftab.c')
| -rw-r--r-- | dotfiles/system/.zsh/modules/Src/aloxaf/fzftab.c | 546 |
1 files changed, 546 insertions, 0 deletions
diff --git a/dotfiles/system/.zsh/modules/Src/aloxaf/fzftab.c b/dotfiles/system/.zsh/modules/Src/aloxaf/fzftab.c new file mode 100644 index 0000000..60b6330 --- /dev/null +++ b/dotfiles/system/.zsh/modules/Src/aloxaf/fzftab.c @@ -0,0 +1,546 @@ +#include "fzftab.mdh" +#include "fzftab.pro" +#include <malloc.h> +#include <stdarg.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <unistd.h> + +const char* get_color(char* file, const struct stat* sb); +const char* get_suffix(char* file, const struct stat* sb); +const char* colorize_from_mode(char* file, const struct stat* sb); +const char* colorize_from_name(char* file); +char** fzf_tab_colorize(char* file); +int compile_patterns(char* nam, char** list_colors); +char* ftb_strcat(char* dst, int n, ...); + +/* Indixes into the terminal string arrays. */ +#define COL_NO 0 +#define COL_FI 1 +#define COL_DI 2 +#define COL_LN 3 +#define COL_PI 4 +#define COL_SO 5 +#define COL_BD 6 +#define COL_CD 7 +#define COL_OR 8 +#define COL_MI 9 +#define COL_SU 10 +#define COL_SG 11 +#define COL_TW 12 +#define COL_OW 13 +#define COL_ST 14 +#define COL_EX 15 +#define COL_LC 16 +#define COL_RC 17 +#define COL_EC 18 +#define COL_TC 19 +#define COL_SP 20 +#define COL_MA 21 +#define COL_HI 22 +#define COL_DU 23 +#define COL_SA 24 + +#define NUM_COLS 25 + +/* Names of the terminal strings. */ +static char* colnames[] = { "no", "fi", "di", "ln", "pi", "so", "bd", "cd", "or", "mi", "su", "sg", + "tw", "ow", "st", "ex", "lc", "rc", "ec", "tc", "sp", "ma", "hi", "du", "sa", NULL }; + +/* Default values. */ +static char* defcols[] + = { "0", "0", "1;31", "1;36", "33", "1;35", "1;33", "1;33", NULL, NULL, "37;41", "30;43", + "30;42", "34;42", "37;44", "1;32", "\033[", "m", NULL, "0", "0", "7", NULL, NULL, "0" }; + +static char* fzf_tab_module_version; + +struct pattern { + Patprog pat; + char color[50]; +}; + +static int opt_list_type = OPT_INVALID; +static int pat_cnt = 0; +static struct pattern* name_color = NULL; +static char mode_color[NUM_COLS][20]; + +// TODO: use ZLS_COLORS ? +int compile_patterns(char* nam, char** list_colors) +{ + // clean old name_color and set pat_cnt = 0 + if (pat_cnt != 0) { + while (--pat_cnt) { + freepatprog(name_color[pat_cnt].pat); + } + free(name_color); + } + // initialize mode_color with default value + for (int i = 0; i < NUM_COLS; i++) { + if (defcols[i]) { + strcpy(mode_color[i], defcols[i]); + } + } + // empty array, just return + if (list_colors == NULL) { + return 0; + } + + // how many pattens? + while (list_colors[pat_cnt] != NULL) { + pat_cnt++; + } + name_color = zshcalloc(pat_cnt * sizeof(struct pattern)); + + for (int i = 0; i < pat_cnt; i++) { + char* pat = ztrdup(list_colors[i]); + char* color = strrchr(pat, '='); + if (color == NULL) + continue; + *color = '\0'; + tokenize(pat); + remnulargs(pat); + + // mode=color + bool skip = false; + for (int j = 0; j < NUM_COLS; j++) { + if (strpfx(colnames[j], list_colors[i])) { + strcpy(mode_color[j], color + 1); + name_color[i].pat = NULL; + skip = true; + } + } + if (skip) { + continue; + } + + // name=color + if (!(name_color[i].pat = patcompile(pat, PAT_ZDUP, NULL))) { + zwarnnam(nam, "bad pattern: %s", list_colors[i]); + return 1; + } + + strcpy(name_color[i].color, color + 1); + free(pat); + } + return 0; +} + +// TODO: use zsh mod_export function `file_type` ? +const char* get_suffix(char* file, const struct stat* sb) +{ + struct stat sb2; + mode_t filemode = sb->st_mode; + + if (S_ISBLK(filemode)) + return "#"; + else if (S_ISCHR(filemode)) + return "%"; + else if (S_ISDIR(filemode)) + return "/"; + else if (S_ISFIFO(filemode)) + return "|"; + else if (S_ISLNK(filemode)) + if (strpfx(mode_color[COL_LN], "target")) { + if (stat(file, &sb2) == -1) { + return "@"; + } + return get_suffix(file, &sb2); + } else { + return "@"; + } + else if (S_ISREG(filemode)) + return (filemode & S_IXUGO) ? "*" : ""; + else if (S_ISSOCK(filemode)) + return "="; + else + return "?"; +} + +const char* get_color(char* file, const struct stat* sb) +{ + // no list-colors, return empty color + if (pat_cnt == 0) { + return ""; + } + const char* ret; + if ((ret = colorize_from_mode(file, sb)) || (ret = colorize_from_name(file))) { + return ret; + } + return mode_color[COL_FI]; +} + +const char* colorize_from_name(char* file) +{ + for (int i = 0; i < pat_cnt; i++) { + if (name_color && name_color[i].pat && pattry(name_color[i].pat, file)) { + return name_color[i].color; + } + } + return NULL; +} + +const char* colorize_from_mode(char* file, const struct stat* sb) +{ + struct stat sb2; + + switch (sb->st_mode & S_IFMT) { + case S_IFDIR: + return mode_color[COL_DI]; + case S_IFLNK: { + if (strpfx(mode_color[COL_LN], "target")) { + if (stat(file, &sb2) == -1) { + return mode_color[COL_OR]; + } + return get_color(file, &sb2); + } + } + case S_IFIFO: + return mode_color[COL_PI]; + case S_IFSOCK: + return mode_color[COL_SO]; + case S_IFBLK: + return mode_color[COL_BD]; + case S_IFCHR: + return mode_color[COL_CD]; + default: + break; + } + + if (sb->st_mode & S_ISUID) { + return mode_color[COL_SU]; + } else if (sb->st_mode & S_ISGID) { + return mode_color[COL_SG]; + // tw ow st ?? + } else if (sb->st_mode & S_IXUSR) { + return mode_color[COL_EX]; + } + + /* Check for suffix alias */ + size_t len = strlen(file); + /* shortest valid suffix format is a.b */ + if (len > 2) { + const char* suf = file + len - 1; + while (suf > file + 1) { + if (suf[-1] == '.') { + if (sufaliastab->getnode(sufaliastab, suf)) { + return mode_color[COL_SA]; + } + break; + } + suf--; + } + } + + return NULL; +} + +struct { + char** array; + size_t len; + size_t size; +} ftb_compcap; + +// Usage: +// initialize fzf-tab-generate-compcap -i +// output to _ftb_compcap fzf-tab-generate-compcap -o +// add a entry fzf-tab-generate-compcap word desc opts +static int bin_fzf_tab_compcap_generate(char* nam, char** args, Options ops, UNUSED(int func)) +{ + if (OPT_ISSET(ops, 'o')) { + // write final result to _ftb_compcap + setaparam("_ftb_compcap", ftb_compcap.array); + ftb_compcap.array = NULL; + return 0; + } else if (OPT_ISSET(ops, 'i')) { + // init + if (ftb_compcap.array) + freearray(ftb_compcap.array); + ftb_compcap.array = zshcalloc(1024 * sizeof(char*)); + ftb_compcap.len = 0, ftb_compcap.size = 1024; + return 0; + } + if (ftb_compcap.array == NULL) { + zwarnnam(nam, "please initialize it first"); + return 1; + } + + // get paramaters + char **words = getaparam(args[0]), **dscrs = getaparam(args[1]), *opts = getsparam(args[2]); + if (!words || !dscrs || !opts) { + zwarnnam(nam, "wrong argument"); + return 1; + } + + char *bs = metafy("\2", 1, META_DUP), *nul = metafy("\0word\0", 6, META_DUP); + size_t dscrs_cnt = arrlen(dscrs); + + for (int i = 0; words[i]; i++) { + // TODO: replace '\n' + char* buffer = zshcalloc(256 * sizeof(char)); + char* dscr = i < dscrs_cnt ? dscrs[i] : words[i]; + + buffer = ftb_strcat(buffer, 5, dscr, bs, opts, nul, words[i]); + ftb_compcap.array[ftb_compcap.len++] = buffer; + + if (ftb_compcap.len == ftb_compcap.size) { + ftb_compcap.array + = zrealloc(ftb_compcap.array, (1024 + ftb_compcap.size) * sizeof(char*)); + ftb_compcap.size += 1024; + memset(ftb_compcap.array + ftb_compcap.size - 1024, 0, 1024 * sizeof(char*)); + } + } + + zsfree(bs); + zsfree(nul); + + return 0; +} + +// cat n string, return the pointer to the new string +// `size` is the size of dst +// dst will be reallocated if is not big enough +char* ftb_strcat(char* dst, int n, ...) +{ + va_list valist; + va_start(valist, n); + + char* final = dst; +#ifdef __linux + size_t size = malloc_usable_size(dst); +#elif __APPLE__ + size_t size = malloc_size(dst); +#endif + size_t max_len = size - 1; + + for (int i = 0, idx = 0; i < n; i++) { + char* src = va_arg(valist, char*); + for (; *src != '\0'; dst++, src++, idx++) { + if (idx == max_len) { + size += size / 2; + final = zrealloc(final, size); + max_len = size - 1; + dst = &final[idx]; + } + *dst = *src; + } + } + *dst = '\0'; + va_end(valist); + + return final; +} + +// accept an +char** fzf_tab_colorize(char* file) +{ + // TODO: can avoid so many zalloc here? + file = unmeta(file); + + struct stat sb; + if (lstat(file, &sb) == -1) { + return NULL; + } + + const char* suffix = ""; + if (isset(opt_list_type)) { + suffix = get_suffix(file, &sb); + } + const char* color = get_color(file, &sb); + + char* symlink = ""; + const char* symcolor = ""; + if ((sb.st_mode & S_IFMT) == S_IFLNK) { + symlink = zalloc(PATH_MAX); + int end = readlink(file, symlink, PATH_MAX); + symlink[end] = '\0'; + if (stat(file, &sb) == -1) { + symcolor = mode_color[COL_OR]; + } else { + char tmp[PATH_MAX]; + realpath(file, tmp); + symcolor = get_color(file, &sb); + } + } + + char** reply = zshcalloc((4 + 1) * sizeof(char*)); + + if (strlen(color) != 0) { + reply[0] = zalloc(128); + reply[1] = zalloc(128); + sprintf(reply[0], "%s%s%s", mode_color[COL_LC], color, mode_color[COL_RC]); + sprintf(reply[1], "%s%s%s", mode_color[COL_LC], "0", mode_color[COL_RC]); + } else { + reply[0] = ztrdup(""); + reply[1] = ztrdup(""); + } + + reply[2] = ztrdup(suffix); + + if (symlink[0] != '\0') { + reply[3] = zalloc(PATH_MAX); + sprintf(reply[3], "%s%s%s%s%s%s%s", mode_color[COL_LC], symcolor, mode_color[COL_RC], + symlink, mode_color[COL_LC], "0", mode_color[COL_RC]); + free(symlink); + } else { + reply[3] = ztrdup(""); + } + for (int i = 0; i < 4; i++) { + reply[i] = metafy(reply[i], -1, META_REALLOC); + } + + return reply; +} + +static int bin_fzf_tab_candidates_generate(char* nam, char** args, Options ops, UNUSED(int func)) +{ + if (OPT_ISSET(ops, 'i')) { + // compile list_colors pattern + if (*args == NULL) { + zwarnnam(nam, "please specify an array"); + return 1; + } else { + char** array = getaparam(*args); + return compile_patterns(nam, array); + } + } + + char **ftb_compcap = getaparam("_ftb_compcap"), **group_colors = getaparam("group_colors"), + *default_color = getsparam("default_color"), *prefix = getsparam("prefix"); + + size_t ftb_compcap_len = arrlen(ftb_compcap); + + char *bs = metafy("\b", 1, META_DUP), *nul = metafy("\0", 1, META_DUP), + *soh = metafy("\2", 1, META_DUP); + + char **candidates = zshcalloc(sizeof(char*) * (ftb_compcap_len + 1)), + *filepath = zshcalloc(PATH_MAX * sizeof(char)), *dpre = zshcalloc(128), + *dsuf = zshcalloc(128); + + char* first_word = zshcalloc(512 * sizeof(char)); + int same_word = 1; + + for (int i = 0; i < ftb_compcap_len; i++) { + char *word = "", *group = NULL, *realdir = NULL; + strcpy(dpre, ""); + strcpy(dsuf, ""); + + // extract all the variables what we need + char** compcap = sepsplit(ftb_compcap[i], soh, 1, 0); + char* desc = compcap[0]; + char** info = sepsplit(compcap[1], nul, 1, 0); + + for (int j = 0; info[j]; j += 2) { + if (!strcmp(info[j], "word")) { + word = info[j + 1]; + // unquote word + parse_subst_string(word); + remnulargs(word); + untokenize(word); + } else if (!strcmp(info[j], "group")) { + group = info[j + 1]; + } else if (!strcmp(info[j], "realdir")) { + realdir = info[j + 1]; + } + } + + // check if all the words are the same + if (i == 0) { + first_word = ftb_strcat(first_word, 1, word); + } else if (same_word && strcmp(word, first_word) != 0) { + same_word = 0; + } + + // add character and color to describe the type of the files + if (realdir) { + filepath = ftb_strcat(filepath, 2, realdir, word); + char** reply = fzf_tab_colorize(filepath); + if (reply != NULL) { + dpre = ftb_strcat(dpre, 2, reply[1], reply[0]); + if (reply[3][0] != '\0') { + dsuf = ftb_strcat(dsuf, 4, reply[1], reply[2], " -> ", reply[3]); + } else { + dsuf = ftb_strcat(dsuf, 2, reply[1], reply[2]); + } + if (dpre[0] != '\0') { + setiparam("colorful", 1); + } + freearray(reply); + } + } + + char* result = zshcalloc(256 * sizeof(char)); + + // add color to description if they have group index + if (group) { + // use strtol ? + char* color = group_colors[atoi(group) - 1]; + // add prefix + result = ftb_strcat( + result, 11, group, bs, color, prefix, dpre, nul, group, bs, desc, nul, dsuf); + } else { + result = ftb_strcat(result, 6, default_color, dpre, nul, desc, nul, dsuf); + } + // quotedzputs(result, stdout); + // putchar('\n'); + candidates[i] = result; + + freearray(info); + freearray(compcap); + } + + setaparam("tcandidates", candidates); + setiparam("same_word", same_word); + zsfree(dpre); + zsfree(dsuf); + zsfree(filepath); + zsfree(first_word); + + return 0; +} + +static struct builtin bintab[] = { + BUILTIN("fzf-tab-compcap-generate", 0, bin_fzf_tab_compcap_generate, 0, -1, 0, "io", NULL), + BUILTIN("fzf-tab-candidates-generate", 0, bin_fzf_tab_candidates_generate, 0, -1, 0, "i", NULL), +}; + +static struct paramdef patab[] = { + STRPARAMDEF("FZF_TAB_MODULE_VERSION", &fzf_tab_module_version), +}; + +// clang-format off +static struct features module_features = { + bintab, sizeof(bintab) / sizeof(*bintab), + NULL, 0, + NULL, 0, + patab, sizeof(patab) / sizeof(*patab), + 0, +}; +// clang-format on + +int setup_(UNUSED(Module m)) { return 0; } + +int features_(Module m, char*** features) +{ + *features = featuresarray(m, &module_features); + return 0; +} + +int enables_(Module m, int** enables) { return handlefeatures(m, &module_features, enables); } + +int boot_(UNUSED(Module m)) +{ + fzf_tab_module_version = ztrdup("0.2.2"); + // different zsh version may have different value of list_type's index + // so query it dynamically + opt_list_type = optlookup("list_types"); + return 0; +} + +int cleanup_(UNUSED(Module m)) { return setfeatureenables(m, &module_features, NULL); } + +int finish_(UNUSED(Module m)) +{ + printf("fzf-tab module unloaded.\n"); + fflush(stdout); + return 0; +} |
