experimental hackfix for non-existing problem ;-)
[k8sterm.git] / src / commands.c
blobb73b1788d8a3ee94e6a49e48528d86a15e68f941
1 ////////////////////////////////////////////////////////////////////////////////
2 static K8Term *oldTerm;
3 static int oldTermIdx;
4 static K8Term *newTerm;
5 static int newTermIdx;
6 static int newTermSwitch;
9 #define CMDLD(_t) (K8T_DATA(_t)->cmdline)
12 typedef void (*CmdHandlerFn) (const char *cmdname, char *argstr);
14 typedef struct {
15 const char *name;
16 CmdHandlerFn fn;
17 } Command;
20 static void cmdPastePrimary (const char *cmdname, char *argstr) {
21 selpaste(curterm, XA_PRIMARY);
25 static void cmdPasteSecondary (const char *cmdname, char *argstr) {
26 selpaste(curterm, XA_SECONDARY);
30 static void cmdPasteClipboard (const char *cmdname, char *argstr) {
31 selpaste(curterm, XA_CLIPBOARD);
35 static void cmdExec (const char *cmdname, char *argstr) {
36 if (curterm != NULL) {
37 if (K8T_DATA(curterm)->execcmd != NULL) free(K8T_DATA(curterm)->execcmd);
38 K8T_DATA(curterm)->execcmd = (argstr[0] ? strdup(argstr) : NULL);
43 static int parseTabArgs (char *argstr, int *noswitch, int nowrap, int idx) {
44 for (;;) {
45 char *arg;
47 while (*argstr && isspace(*argstr)) ++argstr;
48 if (!argstr[0]) break;
49 if (iniParseArguments(argstr, "s-R-", &arg, &argstr) != NULL) break;
51 if (strcasecmp(arg, "noswitch") == 0) *noswitch = 1;
52 else if (strcasecmp(arg, "switch") == 0) *noswitch = 0;
53 else if (strcasecmp(arg, "nowrap") == 0) nowrap = 1;
54 else if (strcasecmp(arg, "wrap") == 0) nowrap = 0;
55 else if (strcasecmp(arg, "first") == 0) idx = 0;
56 else if (strcasecmp(arg, "last") == 0) idx = term_count-1;
57 else if (strcasecmp(arg, "prev") == 0) idx = -1;
58 else if (strcasecmp(arg, "next") == 0) idx = -2;
59 else {
60 long int n = -1;
61 char *eptr;
63 n = strtol(arg, &eptr, 0);
64 if (!eptr[0] && n >= 0 && n < term_count) idx = n;
67 switch (idx) {
68 case -1: // prev
69 if ((idx = termidx-1) < 0) idx = nowrap ? 0 : term_count-1;
70 break;
71 case -2: // next
72 if ((idx = termidx+1) >= term_count) idx = nowrap ? term_count-1 : 0;
73 break;
75 return idx;
79 static void flushNewTerm (void) {
80 if (newTerm != NULL) {
81 if (newTermSwitch && curterm != NULL) curterm->lastActiveTime = mclock_ticks();
82 //curterm = newTerm;
83 //termidx = newTermIdx;
84 k8t_tmInitialize(newTerm, term_array[0]->col, term_array[0]->row, opt_maxhistory);
85 termCreateXPixmap(newTerm);
87 if (k8t_ttyNew(newTerm) != 0) {
88 curterm = oldTerm;
89 termidx = oldTermIdx;
90 termfree(newTermIdx);
91 } else {
92 k8t_selInit(newTerm);
93 k8t_ttyResize(newTerm);
94 if (newTermSwitch) {
95 curterm = NULL;
96 termidx = 0;
97 switchToTerm(newTermIdx, 1);
98 oldTerm = curterm;
99 oldTermIdx = termidx;
100 } else {
101 curterm = oldTerm;
102 termidx = oldTermIdx;
105 newTerm = NULL;
110 static void cmdNewTab (const char *cmdname, char *argstr) {
111 int noswitch = 0, idx;
113 if (opt_disabletabs) return;
114 flushNewTerm();
115 if ((newTerm = k8t_termalloc()) == NULL) return;
116 /*idx =*/ parseTabArgs(argstr, &noswitch, 0, termidx);
117 idx = term_count-1;
118 if (!noswitch) {
119 if (curterm != NULL) curterm->lastActiveTime = mclock_ticks();
120 oldTermIdx = idx;
122 newTermIdx = termidx = idx;
123 curterm = newTerm;
124 newTermSwitch = !noswitch;
128 static void cmdCloseTab (const char *cmdname, char *argstr) {
129 flushNewTerm();
130 if (curterm != NULL && !curterm->dead) kill(K8T_DATA(curterm)->pid, SIGTERM);
134 static void cmdKillTab (const char *cmdname, char *argstr) {
135 flushNewTerm();
136 if (!curterm->dead) kill(K8T_DATA(curterm)->pid, SIGKILL);
140 static void cmdSwitchToTab (const char *cmdname, char *argstr) {
141 int noswitch = 0, idx;
143 flushNewTerm();
144 idx = parseTabArgs(argstr, &noswitch, 0, -666);
145 if (idx >= 0) {
146 switchToTerm(idx, 1);
147 oldTerm = curterm;
148 oldTermIdx = termidx;
153 static void cmdMoveTabTo (const char *cmdname, char *argstr) {
154 int noswitch = 0, idx;
156 flushNewTerm();
157 idx = parseTabArgs(argstr, &noswitch, 0, termidx);
158 if (idx != termidx && idx >= 0 && idx < term_count) {
159 K8Term *t = term_array[termidx];
161 // remove current term
162 for (int f = termidx+1; f < term_count; ++f) term_array[f-1] = term_array[f];
163 // insert term
164 for (int f = term_count-2; f >= idx; --f) term_array[f+1] = term_array[f];
165 term_array[idx] = t;
166 termidx = idx;
167 oldTerm = t;
168 oldTermIdx = idx;
169 fixFirstTab();
170 updateTabBar = 1;
175 static void cmdDefaultFG (const char *cmdname, char *argstr) {
176 char *s = NULL;
177 int c;
179 if (iniParseArguments(argstr, "i{0,511}|s-", &c, &s) == NULL) {
180 if (s != NULL && tolower(s[0]) == 'g') defaultFG = c; else curterm->deffg = c;
185 static void cmdDefaultBG (const char *cmdname, char *argstr) {
186 char *s = NULL;
187 int c;
189 if (iniParseArguments(argstr, "i{0,511}|s-", &c) == NULL) {
190 if (s != NULL && tolower(s[0]) == 'g') {
191 defaultBG = c;
192 } else {
193 curterm->defbg = c;
194 XSetWindowBackground(xw.dpy, xw.win, getColor(curterm->defbg));
195 if (newTerm == NULL) {
196 k8t_tmFullDirty(curterm);
197 k8t_drawTerm(curterm, 1);
198 xclearunused();
205 static void scrollHistory (K8Term *term, int delta) {
206 if (term == NULL || term->maxhistory < 1) return; // no history
207 term->topline += delta;
208 if (term->topline > term->maxhistory) term->topline = term->maxhistory;
209 if (term->topline < 0) term->topline = 0;
210 k8t_tmFullDirty(term);
211 k8t_drawTerm(term, 1);
215 static void cmdScrollHistoryLineUp (const char *cmdname, char *argstr) {
216 scrollHistory(curterm, 1);
220 static void cmdScrollHistoryPageUp (const char *cmdname, char *argstr) {
221 scrollHistory(curterm, curterm->row);
225 static void cmdScrollHistoryLineDown (const char *cmdname, char *argstr) {
226 scrollHistory(curterm, -1);
230 static void cmdScrollHistoryPageDown (const char *cmdname, char *argstr) {
231 scrollHistory(curterm, -curterm->row);
235 static void cmdScrollHistoryTop (const char *cmdname, char *argstr) {
236 scrollHistory(curterm, curterm->linecount);
240 static void cmdScrollHistoryBottom (const char *cmdname, char *argstr) {
241 scrollHistory(curterm, -curterm->linecount);
245 static void cmdCommandMode (const char *cmdname, char *argstr) {
246 if (curterm != NULL) {
247 if (CMDLD(curterm).cmdMode == K8T_CMDMODE_NONE) tcmdlineinit(curterm, &CMDLD(curterm)); else tcmdlinehide(curterm, &CMDLD(curterm));
252 // [show|hide]
253 static void cmdCursor (const char *cmdname, char *argstr) {
254 if (curterm != NULL) {
255 char *s;
257 if (iniParseArguments(argstr, "s!-", &s) != NULL) {
258 tcmdlinemsgf(curterm, &CMDLD(curterm), "cursor is %s", ((curterm->c.state&K8T_CURSOR_HIDE) ? "hidden" : "visible"));
259 } else {
260 if (strcasecmp(s, "show") == 0) curterm->c.state &= ~K8T_CURSOR_HIDE;
261 else if (strcasecmp(s, "hide") == 0) curterm->c.state |= K8T_CURSOR_HIDE;
262 k8t_tmWantRedraw(curterm, 0);
268 static void cmdReset (const char *cmdname, char *argstr) {
269 char *s = NULL;
271 if (curterm != NULL) {
272 if (iniParseArguments(argstr, "|s-", &s) == NULL) {
273 if (s != NULL) {
274 switch (tolower(s[0])) {
275 case 'a': // all
276 k8t_tmResetMode(curterm);
277 return;
278 case 'c': // colors
279 k8t_tmResetAttrs(curterm);
280 return;
281 case 'g': // graphics
282 curterm->mode &= ~(K8T_MODE_GFX0|K8T_MODE_GFX1);
283 curterm->charset = K8T_MODE_GFX0;
284 return;
285 case 'u': // cursor
286 curterm->csaved.state = curterm->c.state = K8T_CURSOR_DEFAULT;
287 return;
291 tcmdlinemsgf(curterm, &CMDLD(curterm), "Reset (a)ll | (c)olor | (g)raphics | c(u)rsor");
296 // [norm|alt]
297 static void cmdScreen (const char *cmdname, char *argstr) {
298 if (curterm != NULL) {
299 char *s;
301 if (iniParseArguments(argstr, "s!-", &s) != NULL) {
302 tcmdlinemsgf(curterm, &CMDLD(curterm), "screen: %s", (K8T_ISSET(curterm, K8T_MODE_ALTSCREEN) ? "alt" : "norm"));
303 } else {
304 if (strcasecmp(s, "norm") == 0) {
305 if (K8T_ISSET(curterm, K8T_MODE_ALTSCREEN)) k8t_tmSwapScreen(curterm);
306 } else if (strcasecmp(s, "alt") == 0) {
307 if (!K8T_ISSET(curterm, K8T_MODE_ALTSCREEN)) k8t_tmSwapScreen(curterm);
314 // [on|off]
315 static void cmdMouseReports (const char *cmdname, char *argstr) {
316 if (curterm != NULL) {
317 int b;
319 if (iniParseArguments(argstr, "b", &b) != NULL) {
320 tcmdlinemsgf(curterm, &CMDLD(curterm), "mouse reports are o%s", (K8T_ISSET(curterm, K8T_MODE_MOUSE) ? "n" : "ff"));
321 } else {
322 if (b) curterm->mode |= K8T_MODE_MOUSEBTN; else curterm->mode &= ~K8T_MODE_MOUSEBTN;
328 static int cmd_parseIntArg (const char *fmt, char *argstr, int *b, int *global, int *toggle) {
329 while (argstr[0]) {
330 char *s = NULL;
332 if (iniParseArguments(argstr, "R-", &argstr) != NULL) break;
333 if (!argstr[0]) break;
335 if (iniParseArguments(argstr, "s!-R-", &s, &argstr) != NULL) break;
336 if (global && tolower(s[0]) == 'g') {
337 *global = 1;
338 } else if (toggle && tolower(s[0]) == 't') {
339 *toggle = 1;
340 } else {
341 if (!b || iniParseArguments(s, fmt, b) != NULL) return -1;
344 return 0;
348 static void cmdUTF8Locale (const char *cmdname, char *argstr) {
349 int b = -1, toggle = 0;
351 if (cmd_parseIntArg("b", argstr, &b, NULL, &toggle) != 0) return;
352 if (b == -1) {
353 tcmdlinemsgf(curterm, &CMDLD(curterm), "UTF8Locale: %s", ((needConversion ? !curterm->needConv : 1) ? "yes" : "no"));
354 } else {
355 if (!needConversion) b = 1;
356 if (curterm != NULL) curterm->needConv = !b;
361 static void cmdAudibleBell (const char *cmdname, char *argstr) {
362 int b = -1, toggle = 0, global = 0;
364 if (curterm == NULL) return;
365 if (cmd_parseIntArg("b", argstr, &b, &global, &toggle) != 0) return;
367 if (b == -1) {
368 tcmdlinemsgf(curterm, &CMDLD(curterm), "AudibleBell: %s", (global ? opt_audiblebell : (curterm->belltype&K8T_BELL_AUDIO)) ? "yes" : "no");
369 } else {
370 if (toggle) {
371 if (global) opt_audiblebell = !opt_audiblebell; else curterm->belltype ^= K8T_BELL_AUDIO;
372 } else {
373 if (global) opt_audiblebell = b; else curterm->belltype = (curterm->belltype&~K8T_BELL_AUDIO)|(b!=0?K8T_BELL_AUDIO:0);
379 static void cmdUrgentBell (const char *cmdname, char *argstr) {
380 int b = -1, toggle = 0, global = 0;
382 if (curterm == NULL) return;
383 if (cmd_parseIntArg("b", argstr, &b, &global, &toggle) != 0) return;
385 if (b == -1) {
386 tcmdlinemsgf(curterm, &CMDLD(curterm), "UrgentBell: %s", (global ? opt_urgentbell : (curterm->belltype&K8T_BELL_URGENT)) ? "yes" : "no");
387 } else {
388 if (toggle) {
389 if (global) opt_urgentbell = !opt_urgentbell; else curterm->belltype ^= K8T_BELL_URGENT;
390 } else {
391 if (global) opt_urgentbell = b; else curterm->belltype = (curterm->belltype&~K8T_BELL_URGENT)|(b!=0?K8T_BELL_URGENT:0);
397 static void cmdMonochrome (const char *cmdname, char *argstr) {
398 int b = -1, global = 0;
400 if (curterm == NULL) return;
401 if (cmd_parseIntArg("i{0,3}", argstr, &b, &global, NULL) != 0) return;
403 if (b == -1) {
404 b = (global ? globalBW : curterm->blackandwhite);
405 tcmdlinemsgf(curterm, &CMDLD(curterm), "Monochrome: %d", b);
406 } else {
407 if (global) {
408 if (b == 3) tcmdlinemsg(curterm, &CMDLD(curterm), "Monochrome-global can't be '3'!");
409 else globalBW = b;
410 } else {
411 curterm->blackandwhite = b;
414 k8t_tmFullDirty(curterm);
415 updateTabBar = 1;
419 static void cmdCursorBlink (const char *cmdname, char *argstr) {
420 int b = -1, global = 0;
422 if (curterm == NULL) return;
423 if (cmd_parseIntArg("i{0,10000}", argstr, &b, &global, NULL) != 0) return;
425 if (b == -1) {
426 b = (global ? opt_cursorBlink : curterm->curblink);
427 tcmdlinemsgf(curterm, &CMDLD(curterm), "CursorBlink: %d", b);
428 } else {
429 if (global) {
430 opt_cursorBlink = b;
431 } else {
432 curterm->curblink = b;
433 curterm->curbhidden = 0;
436 k8t_tmFullDirty(curterm);
437 updateTabBar = 1;
441 static void cmdCursorBlinkInactive (const char *cmdname, char *argstr) {
442 int b = -1, global = 0, toggle = 0, *iptr;
444 if (curterm == NULL) return;
445 if (cmd_parseIntArg("b", argstr, &b, &global, &toggle) != 0) return;
447 iptr = (global ? &opt_cursorBlinkInactive : &curterm->curblinkinactive);
448 if (b != -1) {
449 if (toggle) *iptr = !(*iptr); else *iptr = b;
450 k8t_drawTerm(curterm, 0);
455 static void cmdIgnoreClose (const char *cmdname, char *argstr) {
456 int b = -666;
458 if (curterm == NULL) return;
459 if (cmd_parseIntArg("i{-1,1}", argstr, &b, NULL, NULL) != 0) return;
461 if (b == -666) {
462 tcmdlinemsgf(curterm, &CMDLD(curterm), "IgnoreClose: %d", opt_ignoreclose);
463 } else {
464 opt_ignoreclose = b;
469 static void cmdMaxHistory (const char *cmdname, char *argstr) {
470 int b = -1, global = 0;
472 if (curterm == NULL) return;
473 if (cmd_parseIntArg("i{0,65535}", argstr, &b, &global, NULL) != 0) return;
475 if (b == -1) {
476 tcmdlinemsgf(curterm, &CMDLD(curterm), "MaxHistory: %d", (global?opt_maxhistory:curterm->maxhistory));
477 } else {
478 if (!global) k8t_tmAdjMaxHistory(curterm, b); else opt_maxhistory = b;
483 static void cmdMaxDrawTimeout (const char *cmdname, char *argstr) {
484 int b = -1;
486 if (curterm == NULL) return;
487 if (cmd_parseIntArg("i{100,60000}", argstr, &b, NULL, NULL) != 0) return;
489 if (b == -1) {
490 tcmdlinemsgf(curterm, &CMDLD(curterm), "MaxDrawTimeout: %d", opt_maxdrawtimeout);
491 } else {
492 opt_maxdrawtimeout = b;
497 static void cmdSwapDrawTimeout (const char *cmdname, char *argstr) {
498 int b = -1;
500 if (curterm == NULL) return;
501 if (cmd_parseIntArg("i{10,60000}", argstr, &b, NULL, NULL) != 0) return;
503 if (b == -1) {
504 tcmdlinemsgf(curterm, &CMDLD(curterm), "SwapDrawTimeout: %d", opt_swapdrawtimeout);
505 } else {
506 opt_swapdrawtimeout = b;
511 static void cmdTabPosition (const char *cmdname, char *argstr) {
512 int newpos = -1;
514 while (argstr[0]) {
515 char *s = NULL;
517 if (iniParseArguments(argstr, "R-", &argstr) != NULL) break;
518 if (!argstr[0]) break;
520 if (iniParseArguments(argstr, "s!-R-", &s, &argstr) != NULL) break;
521 if (tolower(s[0]) == 't') newpos = 1;
522 else if (tolower(s[0]) == 'b') newpos = 0;
523 else if (iniParseArguments(s, "i{0,1}", &newpos) != NULL) return;
526 if (newpos == -1) {
527 tcmdlinemsgf(curterm, &CMDLD(curterm), "TabPostion: %s", (opt_tabposition == 0 ? "bottom" : "top"));
528 } else if (opt_tabposition != newpos) {
529 opt_tabposition = newpos;
530 updateTabBar = 1;
531 k8t_tmFullDirty(curterm);
532 k8t_drawTerm(curterm, 1);
533 xdrawTabBar();
534 xclearunused();
539 static void cmdTabCount (const char *cmdname, char *argstr) {
540 int b = -1;
542 if (curterm == NULL) return;
543 if (cmd_parseIntArg("i{1,128}", argstr, &b, NULL, NULL) != 0) return;
545 if (b == -1) {
546 tcmdlinemsgf(curterm, &CMDLD(curterm), "TabCount: %d", opt_tabcount);
547 } else if (opt_tabcount != b) {
548 opt_tabcount = b;
549 fixFirstTab();
550 updateTabBar = 1;
551 xdrawTabBar();
556 static void cmdDoFullRedraw (const char *cmdname, char *argstr) {
557 updateTabBar = 1;
558 k8t_tmFullDirty(curterm);
559 xclearunused();
560 k8t_drawTerm(curterm, 1);
561 xdrawTabBar();
565 static void cmdTitle (const char *cmdname, char *argstr) {
566 if (curterm != NULL) {
567 char *s = NULL;
569 if (iniParseArguments(argstr, "s-", &s) != NULL || s == NULL) return;
570 memset(curterm->title, 0, sizeof(curterm->title));
571 while (strlen(s) > K8T_ESC_TITLE_SIZ) k8t_UTF8ChopLast(s);
572 fprintf(stderr, "[%s]\n", s);
573 strncpy(curterm->title, s, K8T_ESC_TITLE_SIZ);
574 fixWindowTitle(curterm);
575 updateTabBar = 1;
576 xdrawTabBar();
581 static void cmdFastRedraw (const char *cmdname, char *argstr) {
582 int b = -1, global = 0, toggle = 0, *iptr;
584 if (curterm == NULL) return;
585 if (cmd_parseIntArg("b", argstr, &b, &global, &toggle) != 0) return;
587 iptr = (global ? &opt_fastredraw : &curterm->fastredraw);
588 if (b != -1) {
589 if (toggle) *iptr = !(*iptr); else *iptr = b;
590 k8t_drawTerm(curterm, 0);
591 } else {
592 tcmdlinemsgf(curterm, &CMDLD(curterm), "FastRedraw: %s", (*iptr ? "yes" : "no"));
597 static void cmdAbout (const char *cmdname, char *argstr) {
598 if (curterm != NULL) {
599 tcmdlinemsgf(curterm, &CMDLD(curterm), "k8sterm " VERSION);
604 static void cmdDebugDump (const char *cmdname, char *argstr) {
605 if (curterm != NULL) {
606 char *s = NULL;
608 if (iniParseArguments(argstr, "s-", &s) == NULL) {
609 if (s != NULL) {
610 switch (tolower(s[0])) {
611 case 'o': // off
612 case 'n': // none
613 curterm->dumpescapes = 0;
614 curterm->dumpeskeys = 0;
615 return;
616 case 'a': // all
617 curterm->dumpescapes = 1;
618 curterm->dumpeskeys = 1;
619 return;
620 case 'e': // escapes
621 curterm->dumpescapes = !curterm->dumpescapes;
622 return;
623 case 'k': // keys
624 curterm->dumpeskeys = !curterm->dumpeskeys;
625 return;
629 tcmdlinemsgf(curterm, &CMDLD(curterm), "DbgDump (n)one | (a)ll | toggle (e)scapes | toggle extended (k)eys");
634 // 0: none
635 // 1: in center
636 // 2: at left
637 // 3: at right
638 static void cmdTabEllipsis (const char *cmdname, char *argstr) {
639 int b = -1;
641 if (curterm == NULL) return;
642 if (cmd_parseIntArg("i{0,3}", argstr, &b, NULL, NULL) != 0) return;
644 if (b != -1) {
645 if (opt_tabellipsis != b) {
646 opt_tabellipsis = b;
647 updateTabBar = 1;
648 xdrawTabBar();
650 } else {
651 tcmdlinemsgf(curterm, &CMDLD(curterm), "TabEllipsis: %d", opt_tabellipsis);
656 static const Command commandList[] = {
657 {"PastePrimary", cmdPastePrimary},
658 {"PasteSecondary", cmdPasteSecondary},
659 {"PasteClipboard", cmdPasteClipboard},
660 {"exec", cmdExec},
661 {"NewTab", cmdNewTab}, // 'noswitch' 'next' 'prev' 'first' 'last'
662 {"CloseTab", cmdCloseTab},
663 {"KillTab", cmdKillTab},
664 {"SwitchToTab", cmdSwitchToTab}, // 'next' 'prev' 'first' 'last' 'nowrap' 'wrap'
665 {"MoveTabTo", cmdMoveTabTo}, // 'next' 'prev' 'first' 'last' 'nowrap' 'wrap'
666 {"DefaultFG", cmdDefaultFG},
667 {"DefaultBG", cmdDefaultBG},
668 {"ScrollHistoryLineUp", cmdScrollHistoryLineUp},
669 {"ScrollHistoryPageUp", cmdScrollHistoryPageUp},
670 {"ScrollHistoryLineDown", cmdScrollHistoryLineDown},
671 {"ScrollHistoryPageDown", cmdScrollHistoryPageDown},
672 {"ScrollHistoryTop", cmdScrollHistoryTop},
673 {"ScrollHistoryBottom", cmdScrollHistoryBottom},
674 {"UTF8Locale", cmdUTF8Locale}, // 'on', 'off'
675 {"AudibleBell", cmdAudibleBell},
676 {"UrgentBell", cmdUrgentBell},
677 {"CommandMode", cmdCommandMode},
678 {"Cursor", cmdCursor},
679 {"Reset", cmdReset},
680 {"Screen", cmdScreen},
681 {"MouseReports", cmdMouseReports},
682 {"Monochrome", cmdMonochrome},
683 {"Mono", cmdMonochrome},
684 {"CursorBlink", cmdCursorBlink},
685 {"CursorBlinkInactive", cmdCursorBlinkInactive},
686 {"IgnoreClose", cmdIgnoreClose},
687 {"MaxHistory", cmdMaxHistory},
688 {"MaxDrawTimeout", cmdMaxDrawTimeout},
689 {"SwapDrawTimeout", cmdSwapDrawTimeout},
690 {"TabPosition", cmdTabPosition},
691 {"TabCount", cmdTabCount},
692 {"DoFullRedraw", cmdDoFullRedraw},
693 {"Title", cmdTitle},
694 {"FastRedraw", cmdFastRedraw},
695 {"TabEllipsis", cmdTabEllipsis},
697 {"KeyBind", NULL},
698 {"KeyTrans", NULL},
699 {"KeyMap", NULL},
700 {"UniMap", NULL},
702 {"DbgDump", cmdDebugDump},
704 {"About", cmdAbout},
706 {"term", cmdTermName},
707 {"title", cmdWinTitle},
708 {"tabsize", cmdTabSize},
709 {"defaultcursorfg", cmdDefaultCursorFG},
710 {"defaultcursorbg", cmdDefaultCursorBG},
711 {"defaultinactivecursorfg", cmdDefaultInactiveCursorFG},
712 {"defaultinactivecursorbg", cmdDefaultInactiveCursorBG},
713 {"defaultboldfg", cmdDefaultBoldFG},
714 {"defaultunderlinefg", cmdDefaultUnderlineFG},
716 {NULL, NULL}
720 static const char *findCommandCompletion (const char *str, int slen, const char *prev) {
721 const char *res = NULL;
722 int phit = 0;
724 if (slen < 1) return NULL;
725 for (int f = 0; commandList[f].name != NULL; ++f) {
726 if (strlen(commandList[f].name) >= slen && strncasecmp(commandList[f].name, str, slen) == 0) {
727 if (prev == NULL || phit) return commandList[f].name;
728 if (strcasecmp(commandList[f].name, prev) == 0) phit = 1;
729 if (res == NULL) res = commandList[f].name;
732 return res;
736 // !0: NewTab command
737 static int executeCommand (const char *str, int slen) {
738 const char *e;
739 char *cmdname;
740 int cmdfound = 0;
742 if (str == NULL) return 0;
743 if (slen < 0) slen = strlen(str);
745 for (int f = 0; f < slen; ++f) if (!str[f]) { slen = f; break; }
747 while (slen > 0 && isspace(*str)) { ++str; --slen; }
748 if (slen < 1 || !str[0]) return 0;
750 for (e = str; slen > 0 && !isspace(*e); ++e, --slen) ;
752 if (e-str > 127) return 0;
753 cmdname = alloca(e-str+8);
754 if (cmdname == NULL) return 0;
755 memcpy(cmdname, str, e-str);
756 cmdname[e-str] = 0;
757 if (opt_disabletabs && strcasecmp(cmdname, "NewTab") == 0) return 1;
759 while (slen > 0 && isspace(*e)) { ++e; --slen; }
760 //FIXME: ugly copypaste!
762 for (int f = 0; commandList[f].name != NULL; ++f) {
763 if (strcasecmp(commandList[f].name, cmdname) == 0 && commandList[f].fn != NULL) {
764 char *left = calloc(slen+2, 1);
766 if (left != NULL) {
767 if (slen > 0) memcpy(left, e, slen);
768 //fprintf(stderr, "command: [%s]; args: [%s]\n", cmdname, left);
769 commandList[f].fn(cmdname, left);
770 free(left);
772 cmdfound = 1;
773 break;
777 if (!cmdfound) {
778 char *left = calloc(slen+2, 1);
780 if (left != NULL) {
781 if (slen > 0) memcpy(left, e, slen);
782 processMiscCmds(cmdname, left);
783 free(left);
787 return 0;
792 static const char *cmdpSkipStr (const char *str) {
793 while (*str && isspace(*str)) ++str;
794 if (str[0] && str[0] != ';') {
795 char qch = ' ';
797 while (*str) {
798 if (*str == ';' && qch == ' ') break;
799 if (qch != ' ' && *str == qch) { qch = ' '; ++str; continue; }
800 if (*str == '"' || *str == '\'') {
801 if (qch == ' ') qch = *str;
802 ++str;
803 continue;
805 if (*str++ == '\\' && *str) ++str;
808 return str;
813 static void executeCommands (const char *str) {
814 oldTerm = curterm;
815 oldTermIdx = termidx;
816 newTerm = NULL;
817 newTermSwitch = 0;
818 if (str == NULL) return;
819 while (*str) {
820 const char *ce;
821 char qch;
823 while (*str && isspace(*str)) ++str;
824 if (!*str) break;
825 if (*str == ';') { ++str; continue; }
827 ce = str;
828 qch = ' ';
829 while (*ce) {
830 if (*ce == ';' && qch == ' ') break;
831 if (qch != ' ' && *ce == qch) { qch = ' '; ++ce; continue; }
832 if (*ce == '"' || *ce == '\'') {
833 if (qch == ' ') qch = *ce;
834 ++ce;
835 continue;
837 if (*ce++ == '\\' && *ce) ++ce;
840 if (executeCommand(str, ce-str)) break;
841 if (*ce) str = ce+1; else break;
843 flushNewTerm();
844 switchToTerm(oldTermIdx, 1);