diff options
| author | xolatile | 2025-08-06 22:54:55 +0200 |
|---|---|---|
| committer | xolatile | 2025-08-06 22:54:55 +0200 |
| commit | 0a1172b75f571685c264a8b9d8ee224bbf11381f (patch) | |
| tree | d041fdc68a60f0ebb48a3852bbcce6d9432f83d5 /src/engine/console.cpp | |
| parent | affde05dc07a94643f1fd2751b2b441f57f73d7d (diff) | |
| download | xolatile-badassbug-0a1172b75f571685c264a8b9d8ee224bbf11381f.tar.xz xolatile-badassbug-0a1172b75f571685c264a8b9d8ee224bbf11381f.tar.zst | |
Please do not hate me, it makes sense...
Diffstat (limited to 'src/engine/console.cpp')
| -rw-r--r-- | src/engine/console.cpp | 319 |
1 files changed, 96 insertions, 223 deletions
diff --git a/src/engine/console.cpp b/src/engine/console.cpp index c979215..1386570 100644 --- a/src/engine/console.cpp +++ b/src/engine/console.cpp @@ -18,15 +18,12 @@ VARFP(maxcon, 10, 200, MAXCONLINES, { while(conlines.length() > maxcon) delete[] VARP(contags, 0, 3, 3); -void conline(int type, const char *sf) // add a line to the console buffer -{ +void conline(int type, const char *sf) { // add a line to the console buffer { char *buf = NULL; - if(type&CON_TAG_MASK) for(int i = conlines.length()-1; i >= max(conlines.length()-contags, 0); i--) - { + if(type&CON_TAG_MASK) for(int i = conlines.length()-1; i >= max(conlines.length()-contags, 0); i--) { int prev = conlines.removing(i).type; if(!(prev&CON_TAG_MASK)) break; - if(type == prev) - { + if(type == prev) { buf = conlines.remove(i).line; break; } @@ -39,8 +36,7 @@ void conline(int type, const char *sf) // add a line to the console buffer copystring(cl.line, sf, CONSTRLEN); } -void conoutfv(int type, const char *fmt, va_list args) -{ +void conoutfv(int type, const char *fmt, va_list args) { static char buf[CONSTRLEN]; vformatstring(buf, fmt, args, sizeof(buf)); conline(type, buf); @@ -50,10 +46,8 @@ void conoutfv(int type, const char *fmt, va_list args) VAR(fullconsole, 0, 0, 1); ICOMMAND(toggleconsole, "", (), { fullconsole ^= 1; }); -int rendercommand(int x, int y, int w) -{ +int rendercommand(int x, int y, int w) { if(commandmillis < 0) return 0; - defformatstring(s, "%s %s", commandprompt ? commandprompt : ">", commandbuf); int width, height; text_bounds(s, width, height, w); @@ -74,16 +68,13 @@ HVARP(miniconfilter, 0, 0, 0x7FFFFFF); int conskip = 0, miniconskip = 0; -void setconskip(int &skip, int filter, int n) -{ +void setconskip(int &skip, int filter, int n) { filter &= CON_FLAGS; int offset = abs(n), dir = n < 0 ? -1 : 1; skip = clamp(skip, 0, conlines.length()-1); - while(offset) - { + while(offset) { skip += dir; - if(!conlines.inrange(skip)) - { + if(!conlines.inrange(skip)) { skip = clamp(skip, 0, conlines.length()-1); return; } @@ -96,24 +87,18 @@ ICOMMAND(miniconskip, "i", (int *n), setconskip(miniconskip, miniconfilter, *n)) ICOMMAND(clearconsole, "", (), { while(conlines.length()) delete[] conlines.pop().line; }); -int drawconlines(int conskip, int confade, int conwidth, int conheight, int conoff, int filter, int y = 0, int dir = 1) -{ +int drawconlines(int conskip, int confade, int conwidth, int conheight, int conoff, int filter, int y = 0, int dir = 1) { filter &= CON_FLAGS; int numl = conlines.length(), offset = min(conskip, numl); - - if(confade) - { - if(!conskip) - { + if(confade) { + if(!conskip) { numl = 0; loopvrev(conlines) if(totalmillis-conlines[i].outtime < confade*1000) { numl = i+1; break; } } else offset--; } - int totalheight = 0; - loopi(numl) //determine visible height - { + loopi(numl) { //determine visible height { // shuffle backwards to fill if necessary int idx = offset+i < numl ? offset+i : --offset; if(!(conlines[idx].type&filter)) continue; @@ -124,8 +109,7 @@ int drawconlines(int conskip, int confade, int conwidth, int conheight, int cono totalheight += height; } if(dir > 0) y = conoff; - loopi(numl) - { + loopi(numl) { int idx = offset + (dir > 0 ? numl-i-1 : i); if(!(conlines[idx].type&filter)) continue; char *line = conlines[idx].line; @@ -138,16 +122,13 @@ int drawconlines(int conskip, int confade, int conwidth, int conheight, int cono return y+conoff; } -int renderconsole(int w, int h, int abovehud) // render buffer taking into account time & scrolling -{ +int renderconsole(int w, int h, int abovehud) { // render buffer taking into account time & scrolling { int conpad = fullconsole ? 0 : FONTH/4, conoff = fullconsole ? FONTH : FONTH/3, conheight = min(fullconsole ? ((h*fullconsize/100)/FONTH)*FONTH : FONTH*consize, h - 2*(conpad + conoff)), conwidth = w - 2*(conpad + conoff) - (fullconsole ? 0 : game::clipconsole(w, h)); - extern void consolebox(int x1, int y1, int x2, int y2); if(fullconsole) consolebox(conpad, conpad, conwidth+conpad+2*conoff, conheight+conpad+2*conoff); - int y = drawconlines(conskip, fullconsole ? 0 : confade, conwidth, conheight, conpad+conoff, fullconsole ? fullconfilter : confilter); if(!fullconsole && (miniconsize && miniconwidth)) drawconlines(miniconskip, miniconfade, (miniconwidth*(w - 2*(conpad + conoff)))/100, min(FONTH*miniconsize, abovehud - y), conpad+conoff, miniconfilter, abovehud, -1); @@ -156,29 +137,24 @@ int renderconsole(int w, int h, int abovehud) // render buffer taking into // keymap is defined externally in keymap.cfg -struct keym -{ - enum - { +struct keym { + enum { ACTION_DEFAULT = 0, ACTION_SPECTATOR, ACTION_EDITING, NUMACTIONS }; - int code; char *name; char *actions[NUMACTIONS]; bool pressed; - keym() : code(-1), name(NULL), pressed(false) { loopi(NUMACTIONS) actions[i] = newstring(""); } ~keym() { DELETEA(name); loopi(NUMACTIONS) DELETEA(actions[i]); } }; hashtable<int, keym> keyms(128); -void keymap(int *code, char *key) -{ +void keymap(int *code, char *key) { if(identflags&IDF_OVERRIDDEN) { conoutf(CON_ERROR, "cannot override keymap %d", *code); return; } keym &km = keyms[*code]; km.code = *code; @@ -191,19 +167,15 @@ COMMAND(keymap, "is"); keym *keypressed = NULL; char *keyaction = NULL; -const char *getkeyname(int code) -{ +const char *getkeyname(int code) { keym *km = keyms.access(code); return km ? km->name : NULL; } -void searchbinds(char *action, int type) -{ +void searchbinds(char *action, int type) { vector<char> names; - enumerate(keyms, keym, km, - { - if(!strcmp(km.actions[type], action)) - { + enumerate(keyms, keym, km, { + if(!strcmp(km.actions[type], action)) { if(names.length()) names.add(' '); names.put(km.name, strlen(km.name)); } @@ -212,23 +184,19 @@ void searchbinds(char *action, int type) result(names.getbuf()); } -keym *findbind(char *key) -{ - enumerate(keyms, keym, km, - { +keym *findbind(char *key) { + enumerate(keyms, keym, km, { if(!strcasecmp(km.name, key)) return &km; }); return NULL; } -void getbind(char *key, int type) -{ +void getbind(char *key, int type) { keym *km = findbind(key); result(km ? km->actions[type] : ""); } -void bindkey(char *key, char *action, int state, const char *cmd) -{ +void bindkey(char *key, char *action, int state, const char *cmd) { if(identflags&IDF_OVERRIDDEN) { conoutf(CON_ERROR, "cannot override %s \"%s\"", cmd, key); return; } keym *km = findbind(key); if(!km) { conoutf(CON_ERROR, "unknown key \"%s\"", key); return; } @@ -251,8 +219,7 @@ ICOMMAND(searchbinds, "s", (char *action), searchbinds(action, keym::ACTION_DEF ICOMMAND(searchspecbinds, "s", (char *action), searchbinds(action, keym::ACTION_SPECTATOR)); ICOMMAND(searcheditbinds, "s", (char *action), searchbinds(action, keym::ACTION_EDITING)); -void inputcommand(char *init, char *action = NULL, char *prompt = NULL, char *flags = NULL) // turns input to the command line on or off -{ +void inputcommand(char *init, char *action = NULL, char *prompt = NULL, char *flags = NULL) { // turns input to the command line on or off { commandmillis = init ? totalmillis : -1; textinput(commandmillis >= 0, TI_CONSOLE); keyrepeat(commandmillis >= 0, KR_CONSOLE); @@ -263,8 +230,7 @@ void inputcommand(char *init, char *action = NULL, char *prompt = NULL, char *fl if(action && action[0]) commandaction = newstring(action); if(prompt && prompt[0]) commandprompt = newstring(prompt); commandflags = 0; - if(flags) while(*flags) switch(*flags++) - { + if(flags) while(*flags) switch(*flags++) { case 'c': commandflags |= CF_COMPLETE; break; case 'x': commandflags |= CF_EXECUTE; break; case 's': commandflags |= CF_COMPLETE|CF_EXECUTE; break; @@ -275,8 +241,7 @@ void inputcommand(char *init, char *action = NULL, char *prompt = NULL, char *fl ICOMMAND(saycommand, "C", (char *init), inputcommand(init)); COMMAND(inputcommand, "ssss"); -void pasteconsole() -{ +void pasteconsole() { if(!SDL_HasClipboardText()) return; char *cb = SDL_GetClipboardText(); if(!cb) return; @@ -287,21 +252,16 @@ void pasteconsole() SDL_free(cb); } -struct hline -{ +struct hline { char *buf, *action, *prompt; int flags; - hline() : buf(NULL), action(NULL), prompt(NULL), flags(0) {} - ~hline() - { + ~hline() { DELETEA(buf); DELETEA(action); DELETEA(prompt); } - - void restore() - { + void restore() { copystring(commandbuf, buf); if(commandpos >= (int)strlen(commandbuf)) commandpos = -1; DELETEA(commandaction); @@ -310,28 +270,21 @@ struct hline if(prompt) commandprompt = newstring(prompt); commandflags = flags; } - - bool shouldsave() - { + bool shouldsave() { return strcmp(commandbuf, buf) || (commandaction ? !action || strcmp(commandaction, action) : action!=NULL) || (commandprompt ? !prompt || strcmp(commandprompt, prompt) : prompt!=NULL) || commandflags != flags; } - - void save() - { + void save() { buf = newstring(commandbuf); if(commandaction) action = newstring(commandaction); if(commandprompt) prompt = newstring(commandprompt); flags = commandflags; } - - void run() - { + void run() { if(flags&CF_EXECUTE && buf[0]=='/') execute(buf+1); - else if(action) - { + else if(action) { alias("commandbuf", buf); execute(action); } @@ -343,11 +296,9 @@ int histpos = 0; VARP(maxhistory, 0, 1000, 10000); -void history_(int *n) -{ +void history_(int *n) { static bool inhistory = false; - if(!inhistory && history.inrange(*n)) - { + if(!inhistory && history.inrange(*n)) { inhistory = true; history[history.length()-*n-1]->run(); inhistory = false; @@ -356,15 +307,13 @@ void history_(int *n) COMMANDN(history, history_, "i"); -struct releaseaction -{ +struct releaseaction { keym *key; char *action; }; vector<releaseaction> releaseactions; -const char *addreleaseaction(char *s) -{ +const char *addreleaseaction(char *s) { if(!keypressed) { delete[] s; return NULL; } releaseaction &ra = releaseactions.add(); ra.key = keypressed; @@ -372,30 +321,24 @@ const char *addreleaseaction(char *s) return keypressed->name; } -void onrelease(const char *s) -{ +void onrelease(const char *s) { addreleaseaction(newstring(s)); } COMMAND(onrelease, "s"); -void execbind(keym &k, bool isdown) -{ - loopv(releaseactions) - { +void execbind(keym &k, bool isdown) { + loopv(releaseactions) { releaseaction &ra = releaseactions[i]; - if(ra.key==&k) - { + if(ra.key==&k) { if(!isdown) execute(ra.action); delete[] ra.action; releaseactions.remove(i--); } } - if(isdown) - { + if(isdown) { int state = keym::ACTION_DEFAULT; - if(!mainmenu) - { + if(!mainmenu) { if(editmode) state = keym::ACTION_EDITING; else if(player->state==CS_SPECTATOR) state = keym::ACTION_SPECTATOR; } @@ -409,52 +352,39 @@ void execbind(keym &k, bool isdown) k.pressed = isdown; } -bool consoleinput(const char *str, int len) -{ +bool consoleinput(const char *str, int len) { if(commandmillis < 0) return false; - resetcomplete(); int cmdlen = (int)strlen(commandbuf), cmdspace = int(sizeof(commandbuf)) - (cmdlen+1); len = min(len, cmdspace); - if(commandpos<0) - { + if(commandpos<0) { memcpy(&commandbuf[cmdlen], str, len); } - else - { + else { memmove(&commandbuf[commandpos+len], &commandbuf[commandpos], cmdlen - commandpos); memcpy(&commandbuf[commandpos], str, len); commandpos += len; } commandbuf[cmdlen + len] = '\0'; - return true; } -bool consolekey(int code, bool isdown) -{ +bool consolekey(int code, bool isdown) { if(commandmillis < 0) return false; #define MOD_KEYS (KMOD_LCTRL|KMOD_RCTRL) - - if(isdown) - { - switch(code) - { + if(isdown) { + switch(code) { case SDLK_RETURN: case SDLK_KP_ENTER: break; - case SDLK_HOME: if(strlen(commandbuf)) commandpos = 0; break; - case SDLK_END: commandpos = -1; break; - - case SDLK_DELETE: - { + case SDLK_DELETE: { int len = (int)strlen(commandbuf); if(commandpos<0) break; memmove(&commandbuf[commandpos], &commandbuf[commandpos+1], len - commandpos); @@ -462,9 +392,7 @@ bool consolekey(int code, bool isdown) if(commandpos>=len-1) commandpos = -1; break; } - - case SDLK_BACKSPACE: - { + case SDLK_BACKSPACE: { int len = (int)strlen(commandbuf), i = commandpos>=0 ? commandpos : len; if(i<1) break; memmove(&commandbuf[i-1], &commandbuf[i], len - i + 1); @@ -473,49 +401,37 @@ bool consolekey(int code, bool isdown) else if(!commandpos && len<=1) commandpos = -1; break; } - case SDLK_LEFT: if(commandpos>0) commandpos--; else if(commandpos<0) commandpos = (int)strlen(commandbuf)-1; break; - case SDLK_RIGHT: if(commandpos>=0 && ++commandpos>=(int)strlen(commandbuf)) commandpos = -1; break; - case SDLK_UP: if(histpos > history.length()) histpos = history.length(); if(histpos > 0) history[--histpos]->restore(); break; - case SDLK_DOWN: if(histpos + 1 < history.length()) history[++histpos]->restore(); break; - case SDLK_TAB: - if(commandflags&CF_COMPLETE) - { + if(commandflags&CF_COMPLETE) { complete(commandbuf, sizeof(commandbuf), commandflags&CF_EXECUTE ? "/" : NULL); if(commandpos>=0 && commandpos>=(int)strlen(commandbuf)) commandpos = -1; } break; - case SDLK_v: if(SDL_GetModState()&MOD_KEYS) pasteconsole(); break; } } - else - { - if(code==SDLK_RETURN || code==SDLK_KP_ENTER) - { + else { + if(code==SDLK_RETURN || code==SDLK_KP_ENTER) { hline *h = NULL; - if(commandbuf[0]) - { - if(history.empty() || history.last()->shouldsave()) - { - if(maxhistory && history.length() >= maxhistory) - { + if(commandbuf[0]) { + if(history.empty() || history.last()->shouldsave()) { + if(maxhistory && history.length() >= maxhistory) { loopi(history.length()-maxhistory+1) delete history[i]; history.remove(0, history.length()-maxhistory+1); } @@ -527,59 +443,47 @@ bool consolekey(int code, bool isdown) inputcommand(NULL); if(h) h->run(); } - else if(code==SDLK_ESCAPE) - { + else if(code==SDLK_ESCAPE) { histpos = history.length(); inputcommand(NULL); } } - return true; } -void processtextinput(const char *str, int len) -{ +void processtextinput(const char *str, int len) { if(!g3d_input(str, len)) consoleinput(str, len); } -void processkey(int code, bool isdown, int modstate) -{ - switch(code) - { +void processkey(int code, bool isdown, int modstate) { + switch(code) { case SDLK_LGUI: case SDLK_RGUI: return; } keym *haskey = keyms.access(code); if(haskey && haskey->pressed) execbind(*haskey, isdown); // allow pressed keys to release - else if(!g3d_key(code, isdown)) // 3D GUI mouse button intercept - { - if(!consolekey(code, isdown)) - { + else if(!g3d_key(code, isdown)) { // 3D GUI mouse button intercept { + if(!consolekey(code, isdown)) { if(modstate&KMOD_GUI) return; if(haskey) execbind(*haskey, isdown); } } } -void clear_console() -{ +void clear_console() { keyms.clear(); } -void writebinds(stream *f) -{ +void writebinds(stream *f) { static const char * const cmds[3] = { "bind", "specbind", "editbind" }; vector<keym *> binds; enumerate(keyms, keym, km, binds.add(&km)); binds.sortname(); - loopj(3) - { - loopv(binds) - { + loopj(3) { + loopv(binds) { keym &km = *binds[i]; - if(*km.actions[j]) - { + if(*km.actions[j]) { if(validateblock(km.actions[j])) f->printf("%s %s [%s]\n", cmds[j], escapestring(km.name), km.actions[j]); else f->printf("%s %s %s\n", cmds[j], escapestring(km.name), escapestring(km.actions[j])); } @@ -591,42 +495,33 @@ void writebinds(stream *f) enum { FILES_DIR = 0, FILES_VAR, FILES_LIST }; -struct fileskey -{ +struct fileskey { int type; const char *dir, *ext; - fileskey() {} fileskey(int type, const char *dir, const char *ext) : type(type), dir(dir), ext(ext) {} }; -static void cleanfilesdir(char *dir) -{ +static void cleanfilesdir(char *dir) { int dirlen = (int)strlen(dir); while(dirlen > 0 && (dir[dirlen-1] == '/' || dir[dirlen-1] == '\\')) dir[--dirlen] = '\0'; } -struct filesval -{ +struct filesval { int type; char *dir, *ext; vector<char *> files; int millis; - filesval(int type, const char *dir, const char *ext) : type(type), dir(newstring(dir)), ext(ext && ext[0] ? newstring(ext) : NULL), millis(-1) {} ~filesval() { DELETEA(dir); DELETEA(ext); files.deletearrays(); } - - void update() - { + void update() { if((type!=FILES_DIR && type!=FILES_VAR) || millis >= commandmillis) return; files.deletearrays(); - if(type==FILES_VAR) - { + if(type==FILES_VAR) { string buf; buf[0] = '\0'; - if(ident *id = readident(dir)) switch(id->type) - { + if(ident *id = readident(dir)) switch(id->type) { case ID_SVAR: copystring(buf, *id->storage.s); break; case ID_ALIAS: copystring(buf, id->getstr()); break; } @@ -641,13 +536,11 @@ struct filesval } }; -static inline bool htcmp(const fileskey &x, const fileskey &y) -{ +static inline bool htcmp(const fileskey &x, const fileskey &y) { return x.type==y.type && !strcmp(x.dir, y.dir) && (x.ext == y.ext || (x.ext && y.ext && !strcmp(x.ext, y.ext))); } -static inline uint hthash(const fileskey &k) -{ +static inline uint hthash(const fileskey &k) { return hthash(k.dir); } @@ -659,29 +552,24 @@ char *lastcomplete = NULL; void resetcomplete() { completesize = 0; } -void addcomplete(char *command, int type, char *dir, char *ext) -{ - if(identflags&IDF_OVERRIDDEN) - { +void addcomplete(char *command, int type, char *dir, char *ext) { + if(identflags&IDF_OVERRIDDEN) { conoutf(CON_ERROR, "cannot override complete %s", command); return; } - if(!dir[0]) - { + if(!dir[0]) { filesval **hasfiles = completions.access(command); if(hasfiles) *hasfiles = NULL; return; } if(type==FILES_DIR) cleanfilesdir(dir); - if(ext) - { + if(ext) { if(strchr(ext, '*')) ext[0] = '\0'; if(!ext[0]) ext = NULL; } fileskey key(type, dir, ext); filesval **val = completefiles.access(key); - if(!val) - { + if(!val) { filesval *f = new filesval(type, dir, ext); if(type==FILES_LIST) explodelist(dir, f->files); val = &completefiles[fileskey(type, f->dir, f->ext)]; @@ -692,18 +580,15 @@ void addcomplete(char *command, int type, char *dir, char *ext) else completions[newstring(command)] = *val; } -void addfilecomplete(char *command, char *dir, char *ext) -{ +void addfilecomplete(char *command, char *dir, char *ext) { addcomplete(command, FILES_DIR, dir, ext); } -void addvarcomplete(char *command, char *var, char *ext) -{ +void addvarcomplete(char *command, char *var, char *ext) { addcomplete(command, FILES_VAR, var, ext); } -void addlistcomplete(char *command, char *list) -{ +void addlistcomplete(char *command, char *list) { addcomplete(command, FILES_LIST, list, NULL); } @@ -711,31 +596,24 @@ COMMANDN(complete, addfilecomplete, "sss"); COMMANDN(varcomplete, addvarcomplete, "sss"); COMMANDN(listcomplete, addlistcomplete, "ss"); -void complete(char *s, int maxlen, const char *cmdprefix) -{ +void complete(char *s, int maxlen, const char *cmdprefix) { int cmdlen = 0; - if(cmdprefix) - { + if(cmdprefix) { cmdlen = strlen(cmdprefix); if(strncmp(s, cmdprefix, cmdlen)) prependstring(s, cmdprefix, maxlen); } if(!s[cmdlen]) return; if(!completesize) { completesize = (int)strlen(&s[cmdlen]); DELETEA(lastcomplete); } - filesval *f = NULL; - if(completesize) - { + if(completesize) { char *end = strchr(&s[cmdlen], ' '); if(end) f = completions.find(stringslice(&s[cmdlen], end), NULL); } - const char *nextcomplete = NULL; - if(f) // complete using filenames - { + if(f) { // complete using filenames { int commandsize = strchr(&s[cmdlen], ' ')+1-s; f->update(); - loopv(f->files) - { + loopv(f->files) { if(strncmp(f->files[i], &s[commandsize], completesize+cmdlen-commandsize)==0 && (!lastcomplete || strcmp(f->files[i], lastcomplete) > 0) && (!nextcomplete || strcmp(f->files[i], nextcomplete) < 0)) nextcomplete = f->files[i]; @@ -743,8 +621,7 @@ void complete(char *s, int maxlen, const char *cmdprefix) cmdprefix = s; cmdlen = commandsize; } - else // complete using command names - { + else { // complete using command names { enumerate(idents, ident, id, if(strncmp(id.name, &s[cmdlen], completesize)==0 && (!lastcomplete || strcmp(id.name, lastcomplete) > 0) && (!nextcomplete || strcmp(id.name, nextcomplete) < 0)) @@ -752,8 +629,7 @@ void complete(char *s, int maxlen, const char *cmdprefix) ); } DELETEA(lastcomplete); - if(nextcomplete) - { + if(nextcomplete) { cmdlen = min(cmdlen, maxlen-1); if(cmdlen) memmove(s, cmdprefix, cmdlen); copystring(&s[cmdlen], nextcomplete, maxlen-cmdlen); @@ -761,17 +637,14 @@ void complete(char *s, int maxlen, const char *cmdprefix) } } -void writecompletions(stream *f) -{ +void writecompletions(stream *f) { vector<char *> cmds; enumeratekt(completions, char *, k, filesval *, v, { if(v) cmds.add(k); }); cmds.sort(); - loopv(cmds) - { + loopv(cmds) { char *k = cmds[i]; filesval *v = completions[k]; - if(v->type==FILES_LIST) - { + if(v->type==FILES_LIST) { if(validateblock(v->dir)) f->printf("listcomplete %s [%s]\n", escapeid(k), v->dir); else f->printf("listcomplete %s %s\n", escapeid(k), escapestring(v->dir)); } |
