From 3b2535f694c80529c02503bd4c55c71fcf66854a Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Mon, 21 Mar 2022 14:56:52 -0400 Subject: [PATCH] more reorginization --- Rsconscript | 6 + src/edit.1.adoc | 23 -- src/edit.c | 125 ------- src/fetch.1.adoc | 23 -- src/fetch.c | 509 ----------------------------- src/{ => fetchsel}/fetchsel.1.adoc | 0 src/{ => fetchsel}/fetchsel.c | 0 src/pick.1.adoc | 23 -- src/pick.c | 325 ------------------ src/registrar.1.adoc | 17 - src/registrar.c | 294 ----------------- src/{ => tide}/tide.1.adoc | 0 src/{ => tide}/tide.c | 0 13 files changed, 6 insertions(+), 1339 deletions(-) delete mode 100644 src/edit.1.adoc delete mode 100644 src/edit.c delete mode 100644 src/fetch.1.adoc delete mode 100644 src/fetch.c rename src/{ => fetchsel}/fetchsel.1.adoc (100%) rename src/{ => fetchsel}/fetchsel.c (100%) delete mode 100644 src/pick.1.adoc delete mode 100644 src/pick.c delete mode 100644 src/registrar.1.adoc delete mode 100644 src/registrar.c rename src/{ => tide}/tide.1.adoc (100%) rename src/{ => tide}/tide.c (100%) diff --git a/Rsconscript b/Rsconscript index f5f966a..521cf76 100644 --- a/Rsconscript +++ b/Rsconscript @@ -22,6 +22,12 @@ build do env.Program("bin/#{bin}", [src, "libtide.a"]) end + (glob("src/*/") - ["src/lib"]).each do |dir| + bin = File.basename(dir) + env.Program("bin/#{bin}", glob("#{dir}/**/*.c") + ["libtide.a"]) + end + + # Generate the documentation env.Command("", "tools/docgen", "CMD" => ["${_SOURCES}"], diff --git a/src/edit.1.adoc b/src/edit.1.adoc deleted file mode 100644 index eedd942..0000000 --- a/src/edit.1.adoc +++ /dev/null @@ -1,23 +0,0 @@ -= edit(1) -:doctype: manpage - -== NAME - -registrar - registry service for tracking open tide(1) windows - -== SYNOPSIS - -*registrar* - -== DESCRIPTION - - -== OPTIONS - - -== ENVIRONMENT - - -== SEE ALSO - -registrar(1), tide(1), pick(1), fetch(1), fetchsel(1) diff --git a/src/edit.c b/src/edit.c deleted file mode 100644 index c01ad25..0000000 --- a/src/edit.c +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include -#include - -#include "config.h" - -char* ARGV0; -Atom XA_REGISTRAR, XA_OPEN, XA_DONE; - -int spawn(char* cmd) -{ - int pid = fork(); - if (pid == 0) - { - exit(execvp(cmd, (char*[]){cmd, 0})); - } - return pid; -} - -Window start_registrar(XConf* x) -{ - /* launch registrar if it isn't yet running */ - if (None == XGetSelectionOwner(x->display, XA_REGISTRAR)) - { - if (spawn("registrar") > 0) - { - sleep(1); - } - } - return XGetSelectionOwner(x->display, XA_REGISTRAR); -} - -void prop_set(XConf* x, Window win, char* prop, char* value) -{ - Atom xa_prop = XInternAtom(x->display, prop, False); - XChangeProperty( - x->display, win, xa_prop, XA_STRING, 8, PropModeReplace, - (const unsigned char *)value, strlen(value)+1); -} - -void edit_file(XConf* x, Window registrar, char* path, char* addr, int force) -{ - char host[8192]; - path = abspath(path); - prop_set(x, x->self, "FILE", path); - prop_set(x, x->self, "ADDR", addr); - if (!gethostname(host, sizeof(host))) - { - prop_set(x, x->self, "HOST", host); - } - XChangeProperty( - x->display, registrar, XA_OPEN, XA_WINDOW, 32, PropModeAppend, - (const unsigned char *)&(x->self), 1); - EditCmd[2] = addr, EditCmd[3] = path; - if (force) - { - if (!fork()) - exit(execvp(EditCmd[0], EditCmd)); - } - else - { - /* wait for the "done" message */ - for (XEvent e;;) - { - XNextEvent(x->display, &e); - if (e.type == ClientMessage) - { - if (e.xclient.message_type == XA_DONE) - { - break; - } - else if (e.xclient.message_type == XA_OPEN) - { - if (!fork()) - { - exit(execvp(EditCmd[0], EditCmd)); - } - break; - } - } - } - } - free(path); -} - -int main(int argc, char** argv) -{ - int ret = 0; - int force = 0; - OPTBEGIN { case 'f': force = 1; break; } OPTEND; - if (argc == 0) - { - spawn("tide"); - } - else - { - XConf x = {0}; - x11_init(&x); - x11_mkwin(&x, 1, 1, 0); - XA_REGISTRAR = XInternAtom(x.display, "TIDE_REGISTRAR", PropertyChangeMask); - XA_OPEN = XInternAtom(x.display, "OPEN", 0); - XA_DONE = XInternAtom(x.display, "DONE", 0); - Window registrar = start_registrar(&x); - if (registrar != None) - { - /* Loop over files and send an OPEN message for each one. */ - for (int i = 0; i < argc; i++) - { - char* addr = strrchr(argv[i], ':'); - if (addr) - { - *addr = '\0', addr++; - } - edit_file(&x, registrar, argv[i], (addr ? addr : "0"), force); - } - XSync(x.display, False); - } - else - { - fprintf(stderr, "Failed to contact registrar.\n"); - ret = 1; - } - } - return ret; -} diff --git a/src/fetch.1.adoc b/src/fetch.1.adoc deleted file mode 100644 index 527e549..0000000 --- a/src/fetch.1.adoc +++ /dev/null @@ -1,23 +0,0 @@ -= fetch(1) -:doctype: manpage - -== NAME - -registrar - registry service for tracking open tide(1) windows - -== SYNOPSIS - -*registrar* - -== DESCRIPTION - - -== OPTIONS - - -== ENVIRONMENT - - -== SEE ALSO - -registrar(1), tide(1), edit(1), pick(1), fetchsel(1) \ No newline at end of file diff --git a/src/fetch.c b/src/fetch.c deleted file mode 100644 index 3f09d0a..0000000 --- a/src/fetch.c +++ /dev/null @@ -1,509 +0,0 @@ -#include -#include -#include -#include -#include -#include - -typedef struct { - enum { - COMPLETE=0, MATCHES, IS, ISSET, ISDIR, ISFILE, - SET, UNSET, EXEC, LAUNCH - } type; - char* arg1; - char* arg2; -} Rule; - -char* Matches[10]; -Rule*** Rulesets = NULL; -size_t NumRulesets = 0; -bool Launched = false; - -static Rule*** BuiltinRules = (Rule**[]){ - (Rule*[]){ /* Match URLS and open them with the browser */ - &(Rule){ ISSET, "BROWSER", NULL }, - &(Rule){ MATCHES, "data", "^(https?|ftp)://.*" }, - &(Rule){ LAUNCH, "$BROWSER \"$M0\"", NULL }, - &(Rule){ COMPLETE, NULL, NULL } - }, - (Rule*[]){ /* Open files with addresses in the editor */ - &(Rule){ MATCHES, "data", "^([^:]+):([0-9]+)" }, - &(Rule){ ISFILE, "$M1", NULL }, - &(Rule){ LAUNCH, "edit \"$M0\"", NULL }, - &(Rule){ COMPLETE, NULL, NULL } - }, - (Rule*[]){ /* Open addresses in the current file */ - &(Rule){ MATCHES, "data", "^:?([0-9]+)" }, - &(Rule){ ISFILE, "$file", NULL }, - &(Rule){ LAUNCH, "edit \"$file:$M1\"", NULL }, - &(Rule){ COMPLETE, NULL, NULL } - }, - (Rule*[]){ /* If it's an existing text file, open it with editor */ - &(Rule){ ISFILE, "$data", NULL }, - &(Rule){ EXEC, "file --mime \"$file\" | grep -q 'text/'", NULL }, - &(Rule){ LAUNCH, "edit \"$file\"", NULL }, - &(Rule){ COMPLETE, NULL, NULL } - }, - (Rule*[]){ /* Look it up in ctags database */ - &(Rule){ ISFILE, "tags", NULL }, - &(Rule){ EXEC, "grep -q \"^$data\\s\\+\" tags", NULL }, - &(Rule){ LAUNCH, "picktag fetch tags \"$data\"", NULL }, - &(Rule){ COMPLETE, NULL, NULL } - }, - (Rule*[]){ /* Open man pages in a tide window */ - &(Rule){ ISSET, "BROWSER", NULL }, - &(Rule){ MATCHES, "data", "(.+)\\(([0-9]+)\\)" }, - &(Rule){ LAUNCH, "man $M2 \"$M1\" | col -b | tide -", NULL }, - &(Rule){ COMPLETE, NULL, NULL } - }, - (Rule*[]){ /* If it's an existing directory, open it tide */ - &(Rule){ ISDIR, "$data", NULL }, - &(Rule){ LAUNCH, "edit \"$data\"", NULL }, - &(Rule){ COMPLETE, NULL, NULL } - }, - (Rule*[]){ /* look for files in /usr/include */ - &(Rule){ ISFILE, "/usr/include/$data", NULL }, - &(Rule){ LAUNCH, "edit \"/usr/include/$data\"", NULL }, - &(Rule){ COMPLETE, NULL, NULL } - }, - (Rule*[]){ /* look for files in /usr/local/include */ - &(Rule){ ISFILE, "/usr/local/include/$data", NULL }, - &(Rule){ LAUNCH, "edit \"/usr/local/include/$data\"", NULL }, - &(Rule){ COMPLETE, NULL, NULL } - }, - (Rule*[]){ /* look for files in /usr/X11/include */ - &(Rule){ ISFILE, "/usr/X11/include/$data", NULL }, - &(Rule){ LAUNCH, "edit \"/usr/X11/include/$data\"", NULL }, - &(Rule){ COMPLETE, NULL, NULL } - }, - NULL -}; - -static char* homedir_path(char* rpath) -{ - static char path[8192] = {0}; - if (!path[0]) - { - snprintf(path, sizeof(path)-1,"%s/%s", getpwuid(getuid())->pw_dir, rpath); - } - return path; -} - - -/******************************************************************************/ - -char* getvar(char* val) -{ - val = getenv(val); - return (val ? val : ""); -} - -char* eval(char* str) -{ - static bool inited = false; - static char* patt = "\\$([a-zA-Z0-9_]+)"; - static regex_t regex; - - if (!inited && (regcomp(®ex, patt, REG_EXTENDED) < 0)) - { - perror("regcomp() :"); - exit(1); - } - - regmatch_t matches[2] = {{0},{0}}; - int result = regexec(®ex, str, nelem(matches), matches, 0); - if (result >= 0 && matches[1].rm_so > 0) - { - char* var = strndup(str+matches[1].rm_so, matches[1].rm_eo-matches[1].rm_so); - char* val = getvar(var); - size_t sz = strlen(str) + strlen(val); - char* exp = calloc(1, sz); - strncat(exp, str, matches[0].rm_so); - strcat(exp, val); - strcat(exp, str + matches[0].rm_eo); - str = eval(exp); - } - return str; -} - -/******************************************************************************/ - -static bool matches(char* var, char* patt) -{ - bool ret = false; - regex_t regex = {0}; - regmatch_t matches[10] = {{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}}; - if (regcomp(®ex, patt, REG_EXTENDED) == 0) - { - var = getvar(var); - int err = regexec(®ex, var, nelem(matches), matches, 0); - for (int i = 0; i < 10 && matches[i].rm_so >= 0; i++) - { - char* matchval = strndup(var+matches[i].rm_so, matches[i].rm_eo-matches[i].rm_so); - setenv((char[]){ 'M', ('0' + i), 0 }, matchval, 1); - free(matchval); - } - ret = (err == 0); - } - return ret; -} - -static bool var_is(char* var, char* val) -{ - return (strcmp(getvar(var), eval(val)) == 0); -} - -static bool var_isset(char* var) -{ - return (getenv(var) != NULL); -} - -static bool var_isdir(char* var) -{ - bool ret = false; - struct stat st = {0}; - char* path = eval(var); - bool exists = (stat(eval(var), &st) >= 0); - if (exists && S_ISDIR(st.st_mode)) - { - setenv("dir", path, 1); - ret = true; - } - return ret; -} - -static bool var_isfile(char* var) -{ - bool ret = false; - struct stat st = {0}; - char* path = eval(var); - bool exists = (stat(eval(var), &st) >= 0); - if (exists && !S_ISDIR(st.st_mode)) - { - setenv("file", path, 1); - ret = true; - } - return ret; -} - -static bool var_set(char* var, char* val) -{ - return (setenv(var, eval(val), 1) == 0); -} - -static bool var_unset(char* var) -{ - return (unsetenv(var) == 0); -} - -static void runcmd(char* cmd) -{ - char* shellcmd[] = { getvar("SHELL"), "-c", cmd, NULL }; - if (!shellcmd[0]) shellcmd[0] = "/bin/sh"; - _exit(execvp(shellcmd[0], shellcmd)); -} - -static bool exec(char* cmd) -{ - bool ret = false; - int pid, status; - if ((pid = fork()) >= 0) - { - if (pid == 0) - { - runcmd(cmd); - } - else - { - waitpid(pid, &status, 0); - ret = (status == 0); - } - } - return ret; -} - -static bool launch(char* cmd) -{ - bool ret = false; - int pid = fork(); - if (pid > 0) - { - Launched = true; - ret = true; - } - else if (pid == 0) - { - runcmd(cmd); - } - return ret; -} - -static bool apply_rule(Rule* rule) -{ - bool ret = false; - switch (rule->type) - { - case COMPLETE: exit(0); break; - case MATCHES: ret = matches(rule->arg1, rule->arg2); break; - case IS: ret = var_is(rule->arg1, rule->arg2); break; - case ISSET: ret = var_isset(rule->arg1); break; - case ISDIR: ret = var_isdir(rule->arg1); break; - case ISFILE: ret = var_isfile(rule->arg1); break; - case SET: ret = var_set(rule->arg1, rule->arg2); break; - case UNSET: ret = var_unset(rule->arg1); break; - case EXEC: ret = exec(rule->arg1); break; - case LAUNCH: ret = launch(rule->arg1); break; - } - return ret; -} - -/******************************************************************************/ - -static void usage(char* pname) -{ - fprintf(stderr, "Usage: %s [ITEM]\n", pname); - exit(1); -} - -static char* type2str(int type) -{ - char* ret = "UNKNOWN"; - switch (type) - { - case COMPLETE: ret = "COMPLETE"; break; - case MATCHES: ret = "MATCHES"; break; - case IS: ret = "IS"; break; - case ISSET: ret = "ISSET"; break; - case ISDIR: ret = "ISDIR"; break; - case ISFILE: ret = "ISFILE"; break; - case SET: ret = "SET"; break; - case UNSET: ret = "UNSET"; break; - case EXEC: ret = "EXEC"; break; - case LAUNCH: ret = "LAUNCH"; break; - } - return ret; -} - -static char* nextline(char** raw) -{ - char* line = NULL; - char* eol = strchr(*raw, '\n'); - if (eol) - { - *eol = '\0'; - line = *raw; - *raw = eol+1; - } - if (line) - { - line = strdup(line); - } - return line; -} - -static char* nextfield(char** raw) -{ - char* field = *raw; - /* skip whitespace */ - for (; *field && isspace(*field); field++); - - char* eof = field; - for (; *eof && !isspace(*eof); eof++); - *eof = '\0'; - *raw = eof + 1; - - return (field && *field ? field : NULL); -} - -static char* lastfield(char** raw) -{ - char* field = *raw; - /* skip whitespace */ - for (; *field && isspace(*field); field++); - - char* eof = field; - for (; *eof && *eof != '\n'; eof++); - *eof = '\0'; - *raw = eof + 1; - - return (field && *field ? field : NULL); -} - - -static void parse_args1(int type, Rule* rule, char* args) -{ - rule->type = type; - rule->arg1 = args; - if (!rule->arg1) - { - printf("action '%s' requires an argument\n", type2str(type)); - exit(1); - } -} - -static void parse_args2(int type, Rule* rule, char* args) -{ - rule->type = type; - rule->arg1 = nextfield(&args); - rule->arg2 = lastfield(&args); - if (!rule->arg1 || !rule->arg2) - { - printf("action '%s' requires two arguments\n", type2str(type)); - exit(1); - } -} - -static Rule* parse_rule(char* act, char* args) -{ - Rule* rule = calloc(1, sizeof(Rule)); - if (!strcmp(act, "is")) - { - parse_args2(IS, rule, args); - } - else if (!strcmp(act, "isset")) - { - parse_args1(ISSET, rule, args); - } - else if (!strcmp(act, "isdir")) - { - parse_args1(ISDIR, rule, args); - } - else if (!strcmp(act, "isfile")) - { - parse_args1(ISFILE, rule, args); - } - else if (!strcmp(act, "set")) - { - parse_args2(SET, rule, args); - } - else if (!strcmp(act, "unset")) - { - parse_args1(UNSET, rule, args); - } - else if (!strcmp(act, "exec")) - { - parse_args1(EXEC, rule, args); - } - else if (!strcmp(act, "launch")) - { - parse_args1(LAUNCH, rule, args); - } - else if (!strcmp(act, "matches")) - { - parse_args2(MATCHES, rule, args); - } - else - { - printf("error: unknown action '%s'\n", act); - exit(1); - } - return rule; -} - -static void add_ruleset(Rule** rules, size_t nrules, Rule* rule) -{ - if (rules) - { - rules = realloc(rules, sizeof(Rule) * ++nrules); - rules[nrules-1] = rule; - } - Rulesets = realloc(Rulesets, sizeof(Rule) * ++NumRulesets); - Rulesets[NumRulesets-1] = rules; -} - -static void parse_rules(char* path) -{ - char* line = NULL; - char* raw = readfile(path); - telem_send("RULES: %s\n", path); - if (raw) - { - Rule** rules = NULL; - size_t nrules = 0; - - while ((line = nextline(&raw)) != NULL) - { - char* cmd = line; - /* skip whitespace */ - for (; *cmd && isspace(*cmd); cmd++); - - if (!*cmd) - { - add_ruleset(rules, nrules, calloc(1, sizeof(Rule))); - rules = NULL; - nrules = 0; - } - else if (*cmd != '#') - { - char* action = nextfield(&cmd); - rules = realloc(rules, sizeof(Rule) * ++nrules); - rules[nrules-1] = parse_rule(action, cmd); - } - else - { - free(line); - } - line = NULL; - } - - if (rules) - { - add_ruleset(rules, nrules, calloc(1, sizeof(Rule))); - } - } -} - -static void check_ruleset(Rule** rule) -{ - Launched = false; - for (; (*rule)->type != COMPLETE; rule++) - { - telem_send(" RULE(%s '%s' '%s')\n", type2str((*rule)->type), (*rule)->arg1, (*rule)->arg2); - if (!apply_rule(*rule)) - { - break; - } - } - - if (Launched && (*rule)->type == COMPLETE) - { - telem_send(" ACCEPT\n"); - exit(0); - } - else - { - telem_send(" NEXT\n"); - } -} - -int main(int argc, char** argv) -{ - ARGV0 = *argv; - if (argc != 2) - { - usage(ARGV0); - } - else - { - /* load rules from files */ - parse_rules("fetch.rules"); - parse_rules(homedir_path("config/tide/fetch.rules")); - add_ruleset(NULL, 0, NULL); // terminate the parsed set of rules - - telem_send("FETCH(%s)\n", argv[1]); - setenv("data", argv[1], 1); - - /* process parsed rules */ - for (; Rulesets && *Rulesets; Rulesets++) - { - check_ruleset(*Rulesets); - } - - /* process builtin rules */ - for (unsigned int i = 0; BuiltinRules[i]; i++) - { - check_ruleset(BuiltinRules[i]); - } - } - return 1; -} diff --git a/src/fetchsel.1.adoc b/src/fetchsel/fetchsel.1.adoc similarity index 100% rename from src/fetchsel.1.adoc rename to src/fetchsel/fetchsel.1.adoc diff --git a/src/fetchsel.c b/src/fetchsel/fetchsel.c similarity index 100% rename from src/fetchsel.c rename to src/fetchsel/fetchsel.c diff --git a/src/pick.1.adoc b/src/pick.1.adoc deleted file mode 100644 index 5532298..0000000 --- a/src/pick.1.adoc +++ /dev/null @@ -1,23 +0,0 @@ -= pick(1) -:doctype: manpage - -== NAME - -registrar - registry service for tracking open tide(1) windows - -== SYNOPSIS - -*registrar* - -== DESCRIPTION - - -== OPTIONS - - -== ENVIRONMENT - - -== SEE ALSO - -registrar(1), tide(1), edit(1), fetch(1), fetchsel(1) \ No newline at end of file diff --git a/src/pick.c b/src/pick.c deleted file mode 100644 index 8f0655b..0000000 --- a/src/pick.c +++ /dev/null @@ -1,325 +0,0 @@ -#include -#include -#include - -#define INCLUDE_DEFS -#include "config.h" - -static void xkeypress(XConf* x, XEvent* e); -static void xbtnpress(XConf* x, XEvent* e); -static void redraw(XConf* x); -static void xinit(XConf* x); - -typedef struct { - float score; - char* string; - size_t length; - size_t match_start; - size_t match_end; -} Choice; - -char Query[8192] = {0}; -size_t QueryIdx = 0; -vec_t Choices = {0}; -size_t ChoiceIdx = 0; -size_t Offset = 0; - -static int peekc(FILE* in) -{ - int c = fgetc(in); - ungetc(c, in); - return c; -} - -static char* rdline(FILE* fin, size_t* len) -{ - if (feof(fin) || ferror(fin)) - return NULL; - size_t size = 256; - size_t index = 0; - char* str = (char*)calloc(size,1); - while (!feof(stdin)) - { - if (index+2 >= size) - { - size = size << 1; - str = realloc(str, size); - } - char ch = fgetc(fin); - if (ch == '\r') continue; - if (ch == EOF || ch == '\n') break; - str[index++] = ch; - str[index] = '\0'; - } - if (len) *len = index; - return str; -} - -static int by_score(const void* a, const void* b) -{ - Choice* ca = ((Choice*)a); - Choice* cb = ((Choice*)b); - if (ca->score < cb->score) - return 1; - else if (ca->score > cb->score) - return -1; - else - return strcmp(ca->string, cb->string); -} - -static void load_choices(XConf* x) -{ - size_t choice_len; - char* choice_text; - bool shown = false; - Choice choice = {0}; - vec_init(&Choices, sizeof(Choice)); - while ((choice_text = rdline(stdin, &choice_len)) != NULL) - { - if (choice_len > 0) - { - choice.string = choice_text; - choice.length = strlen(choice_text); - choice.score = 1.0; - if (!shown && peekc(stdin) != EOF) - { - x11_show(x); - redraw(x); - shown = true; - } - vec_push_back(&Choices, &choice); - } - else - { - free(choice_text); - } - } -} - -static char* find_char(char* str, int ch) -{ - for (; *str; str++) - if (tolower(*str) == tolower(ch)) - return str; - return NULL; -} - -static inline bool find_match(char *string, char* query, size_t offset, char **start, char **end) -{ - char *s, *e; - /* find first match char or bail */ - s = e = find_char(&string[offset], *query); - if (s == NULL) return false; - - /* find the end of the match */ - for (query++; *query; query++) - if ((e = find_char(e+1, *query)) == NULL) - return false; - - /* if we made it this far, we found a match */ - *start = s, *end = e; - return true; -} - -static bool match(char *string, size_t offset, size_t *start, size_t *end) -{ - char *s1 = 0, *e1 = 0, *s2, *e2; - /* first check if we match at all */ - if (!find_match(string, Query, offset, &s1, &e1)) - return false; - s2 = s1, e2 = e1; // Init s2 and e2 before use below - - /* next find the longest match. If multiple, take the left most one */ - while (find_match(string, Query, ++offset, &s1, &e1) && ((e1-s1) <= (e2-s2))) - s1 = s2, e1 = e2; - - /* return the best match */ - *start = s1 - string; - *end = e1 - string; - return true; -} - -static void score(void) -{ - unsigned int nchoices = vec_size(&Choices); - for (unsigned int i = 0; i < nchoices; i++) { - Choice* choice = (Choice*)vec_at(&Choices, i); - float qlen = (float)QueryIdx; - if (match(choice->string, 0, &choice->match_start, &choice->match_end)) - { - float clen = (float)(choice->match_end - choice->match_start) + 1; - choice->score = qlen / clen / (float)(choice->length); - } - else - { - choice->match_start = 0; - choice->match_end = 0; - choice->score = 0.0f; - } - } - vec_sort(&Choices, by_score); -} - -int main(int argc, char** argv) -{ - XConf x = {0}; - if (argc >= 2) { - size_t sz = min(strlen(argv[1]), sizeof(Query)-1); - strncpy(Query, argv[1], sz); - QueryIdx = sz; - } - xinit(&x); - load_choices(&x); - score(); - if (vec_size(&Choices) > 1) - x11_event_loop(&x, redraw); - Choice* choice = (Choice*)vec_at(&Choices, ChoiceIdx); - if (vec_size(&Choices) && ChoiceIdx != SIZE_MAX) - printf("%s\n", choice->string); - return 0; -} - -static void xkeypress(XConf* x, XEvent* e) -{ - char buf[8]; - KeySym key; - Status status; - if (x->xic) - Xutf8LookupString(x->xic, &(e->xkey), buf, sizeof(buf), &key, &status); - else - XLookupString(&(e->xkey), buf, sizeof(buf), &key, 0); - if (key == XK_Return) - { - x->state = QUITTING; - } - else if (key == XK_Escape) - { - x->state = QUITTING; - ChoiceIdx = SIZE_MAX; - } - else if (key == XK_Up) - { - if (ChoiceIdx > 0) - ChoiceIdx--; - if (ChoiceIdx < Offset) - Offset--; - } - else if (key == XK_Down) - { - size_t nlines = ((x->height - x->font->height - 4) / x->font->height) - 1; - size_t maxidx = Offset + nlines; - if (ChoiceIdx+1 < vec_size(&Choices)) - ChoiceIdx++; - if (ChoiceIdx > maxidx) - Offset++; - } - else if (key == XK_BackSpace) - { - if (QueryIdx > 0) - Query[--QueryIdx] = '\0'; - score(); - } - else if (key >= 0x20 && key <= 0x7F) - { - if (QueryIdx < sizeof(Query)-1) - Query[QueryIdx++] = key; - Offset = ChoiceIdx = 0; - score(); - } -} - -static void xbtnpress(XConf* x, XEvent* e) -{ - (void)x; - if (e->xbutton.button == Button1) - { - int starty = x->font->height + 4; - e->xbutton.y = (e->xbutton.y < starty ? starty : e->xbutton.y - starty); - ChoiceIdx = Offset + (e->xbutton.y / x->font->height); - if (ChoiceIdx >= vec_size(&Choices)) - ChoiceIdx = vec_size(&Choices)-1; - } - else if (e->xbutton.button == Button2) - { - x->state = QUITTING; - } - else if (e->xbutton.button == Button3) - { - x->state = QUITTING; - ChoiceIdx = SIZE_MAX; - } - else if (e->xbutton.button == Button4) - { - if (Offset > 0) Offset--; - } - else if (e->xbutton.button == Button5) - { - if (Offset < vec_size(&Choices)) Offset++; - } -} - -static void redraw(XConf* x) -{ - /* draw the background colors and border */ - size_t fheight = x->font->height; - size_t nlines = ((x->height - x->font->height - 4) / x->font->height) - 1; - size_t scroll_height = x->height - fheight - 4; - size_t start = (size_t)((float)Offset / (float)vec_size(&Choices) * scroll_height); - size_t size = (size_t)((float)nlines / (float)vec_size(&Choices) * scroll_height); - - x11_draw_rect(x, Palette[EditBg], 0, 0, x->width, x->height); - x11_draw_rect(x, Palette[TagsBg], 0, 0, x->width, fheight + 4); - x11_draw_rect(x, Palette[HorBdr], 0, fheight + 4, x->width, 1); - x11_draw_rect(x, Palette[ScrollBg], 0, fheight + 5, ScrollWidth+1, scroll_height); - x11_draw_rect(x, Palette[ScrollFg], 0, fheight + 5 + start, ScrollWidth, (size ? size : 5)); - - /* get size of the query when printed */ - XGlyphInfo glyphinfo; - XftTextExtentsUtf8(x->display, x->font, (const FcChar8*)Query, strlen(Query), &glyphinfo); - int offset = 0; - if (glyphinfo.width >= (x->width - 4)) - offset = ((x->width - 4) - glyphinfo.width); - - /* draw the query and the cursor to the query region */ - int posx = 2 + glyphinfo.width + offset; - x11_draw_rect(x, Palette[TagsFg], posx-1, 2, 3, 3); - x11_draw_rect(x, Palette[TagsFg], posx, 2, 1, fheight); - x11_draw_rect(x, Palette[TagsFg], posx-1, 2+fheight-3, 3, 3); - x11_draw_string(x, x->font, offset + 2, fheight, Palette[TagsFg], Query); - - /* draw the scored and sorted results */ - if (vec_size(&Choices)) - { - for (int i = Offset, y = 2 * fheight + 4; ((size_t)i < vec_size(&Choices)) && ((size_t)i <= Offset+nlines); i++, y += fheight) - { - if ((size_t)i == ChoiceIdx) - x11_draw_rect(x, Palette[EditSel], ScrollWidth+3, y - x->font->ascent, x->width, fheight); - x11_draw_string(x, x->font, ScrollWidth+3, y, Palette[TagsFg], ((Choice*)vec_at(&Choices, i))->string); - } - } - else - { - x11_draw_string(x, x->font, ScrollWidth+3, 2 * fheight + 4, Palette[TagsFg], "Loading..."); - } - x11_flip(x); -} - -static void xinit(XConf* x) -{ - x11_init(x); - x11_mkdialog(x, 640, 480, 0 - | StructureNotifyMask - | KeyPressMask - | ButtonPressMask - | ExposureMask - ); - x11_init_gc(x); - x11_centerwin(x); - if (!(x->font = x11_font_load(x, Fonts[0]))) - { - perror("unable to load base font"); - exit(EXIT_FAILURE); - } - x->eventfns[KeyPress] = xkeypress; - x->eventfns[ButtonPress] = xbtnpress; -} diff --git a/src/registrar.1.adoc b/src/registrar.1.adoc deleted file mode 100644 index 5b9b777..0000000 --- a/src/registrar.1.adoc +++ /dev/null @@ -1,17 +0,0 @@ -= registrar(1) -:doctype: manpage - -== NAME - -registrar - registry service for tracking open tide(1) windows - -== SYNOPSIS - -*registrar* - -== DESCRIPTION - - -== SEE ALSO - -tide(1), edit(1), pick(1), fetch(1), fetchsel(1) \ No newline at end of file diff --git a/src/registrar.c b/src/registrar.c deleted file mode 100644 index f9d4c87..0000000 --- a/src/registrar.c +++ /dev/null @@ -1,294 +0,0 @@ -#include -#include -#include -#include "config.h" - -typedef struct TWindow { - struct TWindow* next; - Window win; - char* path; - char* host; -} TWindow; - -Atom XA_REGISTRAR, XA_ADD, XA_DEL, XA_OPEN, XA_DONE, XA_TIDE; -TWindow* Windows = NULL; - -static void* readprop(XConf* x, Window win, char* prop, Atom type, size_t* length) -{ - Atom rtype, xa_prop = XInternAtom(x->display, prop, False); - int format; - unsigned long datalen, nleft; - unsigned char* data = NULL; - XGetWindowProperty( - x->display, win, xa_prop, 0, -1, False, type, - &rtype, &format, &datalen, &nleft, &data); - if (length) *length = datalen; - if (rtype != type) - { - if (data) XFree(data); - data = 0; - if (length) *length = 0; - } - return (void*)data; -} - -static char* read_path(XConf* x, Window id) -{ - int nprops; - char* path = NULL; - Atom xa_file = XInternAtom(x->display, "FILE", False); - Atom* props = XListProperties(x->display, id, &nprops); - if (props) - { - for (int i = 0; i < nprops; i++) - { - if (props[i] == xa_file) - { - path = readprop(x, id, "FILE", XA_STRING, 0); - break; - } - } - XFree(props); - } - return path; -} - -static void win_add(XConf* x, Window id) -{ - char* path = read_path(x, id); - if (!path) return; - telem_send("WIN_ADD(0x%x: '%s')\n", (unsigned int)id, path); - TWindow* win = calloc(1, sizeof(TWindow)); - win->win = id; - win->next = Windows; - win->path = path; - win->host = readprop(x, id, "HOST", XA_STRING, NULL); - Windows = win; -} - -static void win_del(Window id) -{ - if (!Windows) return; - telem_send("WIN_DEL(0x%x)\n", id); - if (Windows->win == id) - { - TWindow* deadite = Windows; - Windows = deadite->next; - free(deadite); - } - else - { - TWindow* w = Windows; - for (;w && w->next && (w->next->win != id); w = w->next); - if (w && w->next) - { - TWindow* deadite = w->next; - w->next = deadite->next; - free(deadite->path), deadite->path = NULL; - free(deadite->host), deadite->host = NULL; - free(deadite); - } - } -} - -static void win_send(XConf* x, Window from, Window to, int mask, char* atom, size_t val) -{ - telem_send("WIN_SEND(from: %lx, to: %lx, atom: %d)\n", from, to, atom); - XEvent ev = {0}; - ev.xclient.type = ClientMessage; - ev.xclient.send_event = True; - ev.xclient.message_type = XInternAtom(x->display, atom, False); - ev.xclient.window = from; - ev.xclient.format = 32; - ev.xclient.data.l[0] = val; - XSendEvent(x->display, to, False, mask, &ev); -} - -static void win_open(XConf* x, Window winid, char* path, char* addr, char* host) -{ - if (path) - { - telem_send("WIN_OPEN(%lx '%s' '%s')\n", winid, path, host); - /* search for an existing window */ - for (TWindow* win = Windows; win; win = win->next) - { - /* refresh the filepath and crudely determine if window still valid */ - free(win->path); - win->path = NULL; - char* file = readprop(x, win->win, "FILE", XA_STRING, NULL); - win->path = (file ? file : NULL); - telem_send(" %lx '%s' '%s'\n", win->win, win->path, win->host); - if (win->host && !strcmp(win->host, host) && - win->path && !strcmp(win->path, path)) - { - /* double check that the window id didnt get reassigned to a non-tide window */ - telem_send("WIN_ACTIVATE(0x%x '%s')\n", (unsigned int)win->win, win->path); - x11_error_clear(); - char* type = readprop(x, win->win, "TIDE", XA_STRING, 0); - if (!type || x11_error_get()) - { - free(win->path), win->path = NULL; - free(win->host), win->host = NULL; - free(type); - break; - } - else - { - XEvent ev = {0}; - ev.xclient.type = ClientMessage; - ev.xclient.send_event = True; - ev.xclient.message_type = XInternAtom(x->display, "_NET_ACTIVE_WINDOW", False); - ev.xclient.window = win->win; - ev.xclient.format = 32; - ev.xclient.data.l[0] = 1; - ev.xclient.data.l[1] = CurrentTime; - ev.xclient.data.l[2] = 0; - XSendEvent(x->display, x->root, False, SubstructureRedirectMask|SubstructureNotifyMask, &ev); - win_send(x, x->self, win->win, 0, "GOTO", strtoul(addr, NULL, 0)); - win_send(x, x->self, winid, 0, "DONE", 0); - free(type); - return; - } - } - } - - /* if we don't find it, tell sender to spawn a new one */ - win_send(x, x->self, winid, 0, "OPEN", 0); - } -} - -static void selclear(XConf* x, XEvent* e) -{ - (void)e; - XSync(x->display, False); - telem_send("EXITING\n"); - exit(0); -} - -static void clientmsg(XConf* x, XEvent* e) -{ - if (XA_REGISTRAR != e->xclient.message_type) - return; - if (XA_ADD == (Atom)(e->xclient.data.l[0])) - win_add(x, e->xclient.window); - else if (XA_DEL == (Atom)(e->xclient.data.l[0])) - win_del(e->xclient.window); - XSync(x->display, False); -} - -static TWindow* win_sweep(TWindow* win) -{ - if (win) - { - if (win->path) - { - win->next = win_sweep(win->next); - } - else - { - TWindow* dead = win; - telem_send("WIN_SWEEP(%x)\n", (unsigned)win->win); - win = win_sweep(win->next); - free(dead); - } - } - return win; -} - -static void propnotify(XConf* x, XEvent* e) -{ - (void)e; - Atom type; - int format; - unsigned long datalen, nleft; - unsigned char* data = NULL; - XGetWindowProperty( - x->display, x->self, XA_OPEN, 0, -1, True, XA_WINDOW, - &type, &format, &datalen, &nleft, &data); - /* handle all of the window requests */ - for (Window* win = (Window*)data; datalen && win && *win; win++, datalen--) - { - char* file = readprop(x, *win, "FILE", XA_STRING, NULL); - char* addr = readprop(x, *win, "ADDR", XA_STRING, NULL); - char* host = readprop(x, *win, "HOST", XA_STRING, NULL); - win_open(x, *win, file, (addr ? addr : "0"), host); - if(file) XFree(file); - if(addr) XFree(addr); - } - XSync(x->display, False); - - /* cleanup any invalid windows */ - Windows = win_sweep(Windows); -} - -static void find_windows(XConf* x) -{ - XGrabServer(x->display); - size_t nwindows = 0; - Window* windows = readprop(x, x->root, "_NET_CLIENT_LIST", XA_WINDOW, &nwindows); - telem_send("FIND_WINS(nwins: %lu)\n", nwindows); - XUngrabServer(x->display); - for (size_t i = 0; i < nwindows; i++) - win_add(x, windows[i]); - if (windows) XFree(windows); -} - -static int daemonize(void) -{ - int status; - /* fork into the background first */ - if ((status = fork()) < 0) - return -1; - else if (status > 0) - _exit(0); - - /* create a new session */ - if (setsid() < 0) return -1; - - /* fork again so we don't reattach to the terminal */ - if ((status = fork()) < 0) - return -1; - else if (status > 0) - _exit(0); - - /* clear any inherited umask(2) value */ - umask(0); - (void)chdir("/"); - close(0), close(1), close(2); - return 0; -} - -int main(int argc, char** argv) -{ - (void)argc, (void)argv; - ARGV0 = argv[0]; - if (daemonize() >= 0) - { - XConf x = {0}; - x11_init(&x); - x11_mkwin(&x, 1, 1, PropertyChangeMask); - XA_REGISTRAR = XInternAtom(x.display, "TIDE_REGISTRAR", 0); - XA_ADD = XInternAtom(x.display, "ADD", 0); - XA_DEL = XInternAtom(x.display, "DEL", 0); - XA_OPEN = XInternAtom(x.display, "OPEN", 0); - XA_DONE = XInternAtom(x.display, "DONE", 0); - XA_TIDE = XInternAtom(x.display, "TIDE", 0); - x.eventfns[SelectionClear] = selclear; - x.eventfns[ClientMessage] = clientmsg; - x.eventfns[PropertyNotify] = propnotify; - if (None == XGetSelectionOwner(x.display, XA_REGISTRAR)) - { - XSetSelectionOwner(x.display, XA_REGISTRAR, x.self, CurrentTime); - if (x.self == XGetSelectionOwner(x.display, XA_REGISTRAR)) - { - find_windows(&x); - x11_event_loop(&x, 0); - } - else - { - telem_send("FAILED\n"); - } - } - } - return 1; -} diff --git a/src/tide.1.adoc b/src/tide/tide.1.adoc similarity index 100% rename from src/tide.1.adoc rename to src/tide/tide.1.adoc diff --git a/src/tide.c b/src/tide/tide.c similarity index 100% rename from src/tide.c rename to src/tide/tide.c -- 2.52.0