tried to do better scrolling; don't like the result
[k8sterm.git] / src / commands.c
blob22a1c9423918cd53879fb795b2ab2b1e8cbd6d2b
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);
86 //newTerm->drawSetFG(newTerm, newTerm->defbg);
87 k8t_tmFullDirty(newTerm);
89 if (k8t_ttyNew(newTerm) != 0) {
90 curterm = oldTerm;
91 termidx = oldTermIdx;
92 termfree(newTermIdx);
93 } else {
94 k8t_selInit(newTerm);
95 k8t_ttyResize(newTerm);
96 if (newTermSwitch) {
97 curterm = NULL;
98 termidx = 0;
99 switchToTerm(newTermIdx, 1);
100 oldTerm = curterm;
101 oldTermIdx = termidx;
102 } else {
103 curterm = oldTerm;
104 termidx = oldTermIdx;
107 newTerm = NULL;
112 static void cmdNewTab (const char *cmdname, char *argstr) {
113 int noswitch = 0, idx;
115 if (opt_disabletabs) return;
116 flushNewTerm();
117 if ((newTerm = k8t_termalloc()) == NULL) return;
118 k8t_tmInitialize(newTerm, term_array[0]->col, term_array[0]->row, opt_maxhistory);
119 /*idx =*/ parseTabArgs(argstr, &noswitch, 0, termidx);
120 idx = term_count-1;
121 if (!noswitch) {
122 if (curterm != NULL) curterm->lastActiveTime = mclock_ticks();
123 oldTermIdx = idx;
125 newTermIdx = termidx = idx;
126 curterm = newTerm;
127 newTermSwitch = !noswitch;
131 static void cmdCloseTab (const char *cmdname, char *argstr) {
132 flushNewTerm();
133 if (curterm != NULL && !curterm->dead) kill(K8T_DATA(curterm)->pid, SIGTERM);
137 static void cmdKillTab (const char *cmdname, char *argstr) {
138 flushNewTerm();
139 if (!curterm->dead) kill(K8T_DATA(curterm)->pid, SIGKILL);
143 static void cmdSwitchToTab (const char *cmdname, char *argstr) {
144 int noswitch = 0, idx;
146 flushNewTerm();
147 idx = parseTabArgs(argstr, &noswitch, 0, -666);
148 if (idx >= 0) {
149 switchToTerm(idx, 1);
150 oldTerm = curterm;
151 oldTermIdx = termidx;
156 static void cmdMoveTabTo (const char *cmdname, char *argstr) {
157 int noswitch = 0, idx;
159 flushNewTerm();
160 idx = parseTabArgs(argstr, &noswitch, 0, termidx);
161 if (idx != termidx && idx >= 0 && idx < term_count) {
162 K8Term *t = term_array[termidx];
164 // remove current term
165 for (int f = termidx+1; f < term_count; ++f) term_array[f-1] = term_array[f];
166 // insert term
167 for (int f = term_count-2; f >= idx; --f) term_array[f+1] = term_array[f];
168 term_array[idx] = t;
169 termidx = idx;
170 oldTerm = t;
171 oldTermIdx = idx;
172 fixFirstTab();
173 updateTabBar = 1;
178 static void cmdDefaultFG (const char *cmdname, char *argstr) {
179 char *s = NULL;
180 int c;
182 if (iniParseArguments(argstr, "i{0,511}|s-", &c, &s) == NULL) {
183 if (s != NULL && tolower(s[0]) == 'g') defaultFG = c; else curterm->deffg = c;
188 static void cmdDefaultBG (const char *cmdname, char *argstr) {
189 char *s = NULL;
190 int c;
192 if (iniParseArguments(argstr, "i{0,511}|s-", &c) == NULL) {
193 if (s != NULL && tolower(s[0]) == 'g') {
194 defaultBG = c;
195 } else {
196 curterm->defbg = c;
197 XSetWindowBackground(xw.dpy, xw.win, getColor(curterm->defbg));
198 if (newTerm == NULL) {
199 k8t_tmFullDirty(curterm);
200 k8t_drawTerm(curterm, 1);
201 xclearunused();
208 static void scrollHistory (K8Term *term, int delta) {
209 if (term == NULL || term->maxhistory < 1) return; // no history
210 term->topline += delta;
211 if (term->topline > term->maxhistory) term->topline = term->maxhistory;
212 if (term->topline < 0) term->topline = 0;
213 k8t_tmFullDirty(term);
214 k8t_drawTerm(term, 1);
218 static void cmdScrollHistoryLineUp (const char *cmdname, char *argstr) {
219 scrollHistory(curterm, 1);
223 static void cmdScrollHistoryPageUp (const char *cmdname, char *argstr) {
224 scrollHistory(curterm, curterm->row);
228 static void cmdScrollHistoryLineDown (const char *cmdname, char *argstr) {
229 scrollHistory(curterm, -1);
233 static void cmdScrollHistoryPageDown (const char *cmdname, char *argstr) {
234 scrollHistory(curterm, -curterm->row);
238 static void cmdScrollHistoryTop (const char *cmdname, char *argstr) {
239 scrollHistory(curterm, curterm->linecount);
243 static void cmdScrollHistoryBottom (const char *cmdname, char *argstr) {
244 scrollHistory(curterm, -curterm->linecount);
248 static void cmdCommandMode (const char *cmdname, char *argstr) {
249 if (curterm != NULL) {
250 if (CMDLD(curterm).cmdMode == K8T_CMDMODE_NONE) tcmdlineinit(curterm, &CMDLD(curterm)); else tcmdlinehide(curterm, &CMDLD(curterm));
255 // [show|hide]
256 static void cmdCursor (const char *cmdname, char *argstr) {
257 if (curterm != NULL) {
258 char *s;
260 if (iniParseArguments(argstr, "s!-", &s) != NULL) {
261 tcmdlinemsgf(curterm, &CMDLD(curterm), "cursor is %s", ((curterm->c.state&K8T_CURSOR_HIDE) ? "hidden" : "visible"));
262 } else {
263 if (strcasecmp(s, "show") == 0) curterm->c.state &= ~K8T_CURSOR_HIDE;
264 else if (strcasecmp(s, "hide") == 0) curterm->c.state |= K8T_CURSOR_HIDE;
265 k8t_tmWantRedraw(curterm, 0);
271 static void cmdReset (const char *cmdname, char *argstr) {
272 char *s = NULL;
274 if (curterm != NULL) {
275 if (iniParseArguments(argstr, "|s-", &s) == NULL) {
276 if (s != NULL) {
277 switch (tolower(s[0])) {
278 case 'a': // all
279 k8t_tmResetMode(curterm);
280 return;
281 case 'c': // colors
282 k8t_tmResetAttrs(curterm);
283 return;
284 case 'g': // graphics
285 curterm->mode &= ~(K8T_MODE_GFX0|K8T_MODE_GFX1);
286 curterm->charset = K8T_MODE_GFX0;
287 return;
288 case 'u': // cursor
289 curterm->csaved.state = curterm->c.state = K8T_CURSOR_DEFAULT;
290 return;
294 tcmdlinemsgf(curterm, &CMDLD(curterm), "Reset (a)ll | (c)olor | (g)raphics | c(u)rsor");
299 // [norm|alt]
300 static void cmdScreen (const char *cmdname, char *argstr) {
301 if (curterm != NULL) {
302 char *s;
304 if (iniParseArguments(argstr, "s!-", &s) != NULL) {
305 tcmdlinemsgf(curterm, &CMDLD(curterm), "screen: %s", (K8T_ISSET(curterm, K8T_MODE_ALTSCREEN) ? "alt" : "norm"));
306 } else {
307 if (strcasecmp(s, "norm") == 0) {
308 if (K8T_ISSET(curterm, K8T_MODE_ALTSCREEN)) k8t_tmSwapScreen(curterm);
309 } else if (strcasecmp(s, "alt") == 0) {
310 if (!K8T_ISSET(curterm, K8T_MODE_ALTSCREEN)) k8t_tmSwapScreen(curterm);
317 // [on|off]
318 static void cmdMouseReports (const char *cmdname, char *argstr) {
319 if (curterm != NULL) {
320 int b;
322 if (iniParseArguments(argstr, "b", &b) != NULL) {
323 tcmdlinemsgf(curterm, &CMDLD(curterm), "mouse reports are o%s", (K8T_ISSET(curterm, K8T_MODE_MOUSE) ? "n" : "ff"));
324 } else {
325 if (b) curterm->mode |= K8T_MODE_MOUSEBTN; else curterm->mode &= ~K8T_MODE_MOUSEBTN;
331 static int cmd_parseIntArg (const char *fmt, char *argstr, int *b, int *global, int *toggle) {
332 while (argstr[0]) {
333 char *s = NULL;
335 if (iniParseArguments(argstr, "R-", &argstr) != NULL) break;
336 if (!argstr[0]) break;
338 if (iniParseArguments(argstr, "s!-R-", &s, &argstr) != NULL) break;
339 if (global && tolower(s[0]) == 'g') {
340 *global = 1;
341 } else if (toggle && tolower(s[0]) == 't') {
342 *toggle = 1;
343 } else {
344 if (!b || iniParseArguments(s, fmt, b) != NULL) return -1;
347 return 0;
351 static void cmdUTF8Locale (const char *cmdname, char *argstr) {
352 int b = -1, toggle = 0;
354 if (cmd_parseIntArg("b", argstr, &b, NULL, &toggle) != 0) return;
355 if (b == -1) {
356 tcmdlinemsgf(curterm, &CMDLD(curterm), "UTF8Locale: %s", ((needConversion ? !curterm->needConv : 1) ? "yes" : "no"));
357 } else {
358 if (!needConversion) b = 1;
359 if (curterm != NULL) curterm->needConv = !b;
364 static void cmdAudibleBell (const char *cmdname, char *argstr) {
365 int b = -1, toggle = 0, global = 0;
367 if (curterm == NULL) return;
368 if (cmd_parseIntArg("b", argstr, &b, &global, &toggle) != 0) return;
370 if (b == -1) {
371 tcmdlinemsgf(curterm, &CMDLD(curterm), "AudibleBell: %s", (global ? opt_audiblebell : (curterm->belltype&K8T_BELL_AUDIO)) ? "yes" : "no");
372 } else {
373 if (toggle) {
374 if (global) opt_audiblebell = !opt_audiblebell; else curterm->belltype ^= K8T_BELL_AUDIO;
375 } else {
376 if (global) opt_audiblebell = b; else curterm->belltype = (curterm->belltype&~K8T_BELL_AUDIO)|(b!=0?K8T_BELL_AUDIO:0);
382 static void cmdUrgentBell (const char *cmdname, char *argstr) {
383 int b = -1, toggle = 0, global = 0;
385 if (curterm == NULL) return;
386 if (cmd_parseIntArg("b", argstr, &b, &global, &toggle) != 0) return;
388 if (b == -1) {
389 tcmdlinemsgf(curterm, &CMDLD(curterm), "UrgentBell: %s", (global ? opt_urgentbell : (curterm->belltype&K8T_BELL_URGENT)) ? "yes" : "no");
390 } else {
391 if (toggle) {
392 if (global) opt_urgentbell = !opt_urgentbell; else curterm->belltype ^= K8T_BELL_URGENT;
393 } else {
394 if (global) opt_urgentbell = b; else curterm->belltype = (curterm->belltype&~K8T_BELL_URGENT)|(b!=0?K8T_BELL_URGENT:0);
400 static void cmdMonochrome (const char *cmdname, char *argstr) {
401 int b = -1, global = 0;
403 if (curterm == NULL) return;
404 if (cmd_parseIntArg("i{0,3}", argstr, &b, &global, NULL) != 0) return;
406 if (b == -1) {
407 b = (global ? globalBW : curterm->blackandwhite);
408 tcmdlinemsgf(curterm, &CMDLD(curterm), "Monochrome: %d", b);
409 } else {
410 if (global) {
411 if (b == 3) tcmdlinemsg(curterm, &CMDLD(curterm), "Monochrome-global can't be '3'!");
412 else globalBW = b;
413 } else {
414 curterm->blackandwhite = b;
417 k8t_tmFullDirty(curterm);
418 updateTabBar = 1;
422 static void cmdCursorBlink (const char *cmdname, char *argstr) {
423 int b = -1, global = 0;
425 if (curterm == NULL) return;
426 if (cmd_parseIntArg("i{0,10000}", argstr, &b, &global, NULL) != 0) return;
428 if (b == -1) {
429 b = (global ? opt_cursorBlink : curterm->curblink);
430 tcmdlinemsgf(curterm, &CMDLD(curterm), "CursorBlink: %d", b);
431 } else {
432 if (global) {
433 opt_cursorBlink = b;
434 } else {
435 curterm->curblink = b;
436 curterm->curbhidden = 0;
439 k8t_tmFullDirty(curterm);
440 updateTabBar = 1;
444 static void cmdCursorBlinkInactive (const char *cmdname, char *argstr) {
445 int b = -1, global = 0, toggle = 0, *iptr;
447 if (curterm == NULL) return;
448 if (cmd_parseIntArg("b", argstr, &b, &global, &toggle) != 0) return;
450 iptr = (global ? &opt_cursorBlinkInactive : &curterm->curblinkinactive);
451 if (b != -1) {
452 if (toggle) *iptr = !(*iptr); else *iptr = b;
453 k8t_drawTerm(curterm, 0);
458 static void cmdIgnoreClose (const char *cmdname, char *argstr) {
459 int b = -666;
461 if (curterm == NULL) return;
462 if (cmd_parseIntArg("i{-1,1}", argstr, &b, NULL, NULL) != 0) return;
464 if (b == -666) {
465 tcmdlinemsgf(curterm, &CMDLD(curterm), "IgnoreClose: %d", opt_ignoreclose);
466 } else {
467 opt_ignoreclose = b;
472 static void cmdMaxHistory (const char *cmdname, char *argstr) {
473 int b = -1, global = 0;
475 if (curterm == NULL) return;
476 if (cmd_parseIntArg("i{0,65535}", argstr, &b, &global, NULL) != 0) return;
478 if (b == -1) {
479 tcmdlinemsgf(curterm, &CMDLD(curterm), "MaxHistory: %d", (global?opt_maxhistory:curterm->maxhistory));
480 } else {
481 if (!global) k8t_tmAdjMaxHistory(curterm, b); else opt_maxhistory = b;
486 static void cmdMaxDrawTimeout (const char *cmdname, char *argstr) {
487 int b = -1;
489 if (curterm == NULL) return;
490 if (cmd_parseIntArg("i{100,60000}", argstr, &b, NULL, NULL) != 0) return;
492 if (b == -1) {
493 tcmdlinemsgf(curterm, &CMDLD(curterm), "MaxDrawTimeout: %d", opt_maxdrawtimeout);
494 } else {
495 opt_maxdrawtimeout = b;
500 static void cmdSwapDrawTimeout (const char *cmdname, char *argstr) {
501 int b = -1;
503 if (curterm == NULL) return;
504 if (cmd_parseIntArg("i{10,60000}", argstr, &b, NULL, NULL) != 0) return;
506 if (b == -1) {
507 tcmdlinemsgf(curterm, &CMDLD(curterm), "SwapDrawTimeout: %d", opt_swapdrawtimeout);
508 } else {
509 opt_swapdrawtimeout = b;
514 static void cmdTabPosition (const char *cmdname, char *argstr) {
515 int newpos = -1;
517 while (argstr[0]) {
518 char *s = NULL;
520 if (iniParseArguments(argstr, "R-", &argstr) != NULL) break;
521 if (!argstr[0]) break;
523 if (iniParseArguments(argstr, "s!-R-", &s, &argstr) != NULL) break;
524 if (tolower(s[0]) == 't') newpos = 1;
525 else if (tolower(s[0]) == 'b') newpos = 0;
526 else if (iniParseArguments(s, "i{0,1}", &newpos) != NULL) return;
529 if (newpos == -1) {
530 tcmdlinemsgf(curterm, &CMDLD(curterm), "TabPostion: %s", (opt_tabposition == 0 ? "bottom" : "top"));
531 } else if (opt_tabposition != newpos) {
532 opt_tabposition = newpos;
533 updateTabBar = 1;
534 k8t_tmFullDirty(curterm);
535 k8t_drawTerm(curterm, 1);
536 xdrawTabBar();
537 xclearunused();
542 static void cmdTabCount (const char *cmdname, char *argstr) {
543 int b = -1;
545 if (curterm == NULL) return;
546 if (cmd_parseIntArg("i{1,128}", argstr, &b, NULL, NULL) != 0) return;
548 if (b == -1) {
549 tcmdlinemsgf(curterm, &CMDLD(curterm), "TabCount: %d", opt_tabcount);
550 } else if (opt_tabcount != b) {
551 opt_tabcount = b;
552 fixFirstTab();
553 updateTabBar = 1;
554 xdrawTabBar();
559 static void cmdDoFullRedraw (const char *cmdname, char *argstr) {
560 updateTabBar = 1;
561 k8t_tmFullDirty(curterm);
562 xclearunused();
563 k8t_drawTerm(curterm, 1);
564 xdrawTabBar();
568 static void cmdTitle (const char *cmdname, char *argstr) {
569 if (curterm != NULL) {
570 char *s = NULL;
572 if (iniParseArguments(argstr, "s-", &s) != NULL || s == NULL) return;
573 memset(curterm->title, 0, sizeof(curterm->title));
574 while (strlen(s) > K8T_ESC_TITLE_SIZ) k8t_UTF8ChopLast(s);
575 fprintf(stderr, "[%s]\n", s);
576 strncpy(curterm->title, s, K8T_ESC_TITLE_SIZ);
577 fixWindowTitle(curterm);
578 updateTabBar = 1;
579 xdrawTabBar();
584 static void cmdFastRedraw (const char *cmdname, char *argstr) {
585 int b = -1, global = 0, toggle = 0, *iptr;
587 if (curterm == NULL) return;
588 if (cmd_parseIntArg("b", argstr, &b, &global, &toggle) != 0) return;
590 iptr = (global ? &opt_fastredraw : &curterm->fastredraw);
591 if (b != -1) {
592 if (toggle) *iptr = !(*iptr); else *iptr = b;
593 k8t_drawTerm(curterm, 0);
594 } else {
595 tcmdlinemsgf(curterm, &CMDLD(curterm), "FastRedraw: %s", (*iptr ? "yes" : "no"));
600 static void cmdAbout (const char *cmdname, char *argstr) {
601 if (curterm != NULL) {
602 tcmdlinemsgf(curterm, &CMDLD(curterm), "k8sterm " VERSION);
607 static void cmdDebugDump (const char *cmdname, char *argstr) {
608 if (curterm != NULL) {
609 char *s = NULL;
611 if (iniParseArguments(argstr, "s-", &s) == NULL) {
612 if (s != NULL) {
613 switch (tolower(s[0])) {
614 case 'o': // off
615 case 'n': // none
616 curterm->dumpescapes = 0;
617 curterm->dumpeskeys = 0;
618 return;
619 case 'a': // all
620 curterm->dumpescapes = 1;
621 curterm->dumpeskeys = 1;
622 return;
623 case 'e': // escapes
624 curterm->dumpescapes = !curterm->dumpescapes;
625 return;
626 case 'k': // keys
627 curterm->dumpeskeys = !curterm->dumpeskeys;
628 return;
632 tcmdlinemsgf(curterm, &CMDLD(curterm), "DbgDump (n)one | (a)ll | toggle (e)scapes | toggle extended (k)eys");
637 // 0: none
638 // 1: in center
639 // 2: at left
640 // 3: at right
641 static void cmdTabEllipsis (const char *cmdname, char *argstr) {
642 int b = -1;
644 if (curterm == NULL) return;
645 if (cmd_parseIntArg("i{0,3}", argstr, &b, NULL, NULL) != 0) return;
647 if (b != -1) {
648 if (opt_tabellipsis != b) {
649 opt_tabellipsis = b;
650 updateTabBar = 1;
651 xdrawTabBar();
653 } else {
654 tcmdlinemsgf(curterm, &CMDLD(curterm), "TabEllipsis: %d", opt_tabellipsis);
659 static const Command commandList[] = {
660 {"PastePrimary", cmdPastePrimary},
661 {"PasteSecondary", cmdPasteSecondary},
662 {"PasteClipboard", cmdPasteClipboard},
663 {"exec", cmdExec},
664 {"NewTab", cmdNewTab}, // 'noswitch' 'next' 'prev' 'first' 'last'
665 {"CloseTab", cmdCloseTab},
666 {"KillTab", cmdKillTab},
667 {"SwitchToTab", cmdSwitchToTab}, // 'next' 'prev' 'first' 'last' 'nowrap' 'wrap'
668 {"MoveTabTo", cmdMoveTabTo}, // 'next' 'prev' 'first' 'last' 'nowrap' 'wrap'
669 {"DefaultFG", cmdDefaultFG},
670 {"DefaultBG", cmdDefaultBG},
671 {"ScrollHistoryLineUp", cmdScrollHistoryLineUp},
672 {"ScrollHistoryPageUp", cmdScrollHistoryPageUp},
673 {"ScrollHistoryLineDown", cmdScrollHistoryLineDown},
674 {"ScrollHistoryPageDown", cmdScrollHistoryPageDown},
675 {"ScrollHistoryTop", cmdScrollHistoryTop},
676 {"ScrollHistoryBottom", cmdScrollHistoryBottom},
677 {"UTF8Locale", cmdUTF8Locale}, // 'on', 'off'
678 {"AudibleBell", cmdAudibleBell},
679 {"UrgentBell", cmdUrgentBell},
680 {"CommandMode", cmdCommandMode},
681 {"Cursor", cmdCursor},
682 {"Reset", cmdReset},
683 {"Screen", cmdScreen},
684 {"MouseReports", cmdMouseReports},
685 {"Monochrome", cmdMonochrome},
686 {"Mono", cmdMonochrome},
687 {"CursorBlink", cmdCursorBlink},
688 {"CursorBlinkInactive", cmdCursorBlinkInactive},
689 {"IgnoreClose", cmdIgnoreClose},
690 {"MaxHistory", cmdMaxHistory},
691 {"MaxDrawTimeout", cmdMaxDrawTimeout},
692 {"SwapDrawTimeout", cmdSwapDrawTimeout},
693 {"TabPosition", cmdTabPosition},
694 {"TabCount", cmdTabCount},
695 {"DoFullRedraw", cmdDoFullRedraw},
696 {"Title", cmdTitle},
697 {"FastRedraw", cmdFastRedraw},
698 {"TabEllipsis", cmdTabEllipsis},
700 {"KeyBind", NULL},
701 {"KeyTrans", NULL},
702 {"KeyMap", NULL},
703 {"UniMap", NULL},
705 {"DbgDump", cmdDebugDump},
707 {"About", cmdAbout},
709 {"term", cmdTermName},
710 {"title", cmdWinTitle},
711 {"tabsize", cmdTabSize},
712 {"defaultcursorfg", cmdDefaultCursorFG},
713 {"defaultcursorbg", cmdDefaultCursorBG},
714 {"defaultinactivecursorfg", cmdDefaultInactiveCursorFG},
715 {"defaultinactivecursorbg", cmdDefaultInactiveCursorBG},
716 {"defaultboldfg", cmdDefaultBoldFG},
717 {"defaultunderlinefg", cmdDefaultUnderlineFG},
719 {NULL, NULL}
723 static const char *findCommandCompletion (const char *str, int slen, const char *prev) {
724 const char *res = NULL;
725 int phit = 0;
727 if (slen < 1) return NULL;
728 for (int f = 0; commandList[f].name != NULL; ++f) {
729 if (strlen(commandList[f].name) >= slen && strncasecmp(commandList[f].name, str, slen) == 0) {
730 if (prev == NULL || phit) return commandList[f].name;
731 if (strcasecmp(commandList[f].name, prev) == 0) phit = 1;
732 if (res == NULL) res = commandList[f].name;
735 return res;
739 // !0: NewTab command
740 static int executeCommand (const char *str, int slen) {
741 const char *e;
742 char *cmdname;
743 int cmdfound = 0;
745 if (str == NULL) return 0;
746 if (slen < 0) slen = strlen(str);
748 for (int f = 0; f < slen; ++f) if (!str[f]) { slen = f; break; }
750 while (slen > 0 && isspace(*str)) { ++str; --slen; }
751 if (slen < 1 || !str[0]) return 0;
753 for (e = str; slen > 0 && !isspace(*e); ++e, --slen) ;
755 if (e-str > 127) return 0;
756 cmdname = alloca(e-str+8);
757 if (cmdname == NULL) return 0;
758 memcpy(cmdname, str, e-str);
759 cmdname[e-str] = 0;
760 if (opt_disabletabs && strcasecmp(cmdname, "NewTab") == 0) return 1;
762 while (slen > 0 && isspace(*e)) { ++e; --slen; }
763 //FIXME: ugly copypaste!
765 for (int f = 0; commandList[f].name != NULL; ++f) {
766 if (strcasecmp(commandList[f].name, cmdname) == 0 && commandList[f].fn != NULL) {
767 char *left = calloc(slen+2, 1);
769 if (left != NULL) {
770 if (slen > 0) memcpy(left, e, slen);
771 //fprintf(stderr, "command: [%s]; args: [%s]\n", cmdname, left);
772 commandList[f].fn(cmdname, left);
773 free(left);
775 cmdfound = 1;
776 break;
780 if (!cmdfound) {
781 char *left = calloc(slen+2, 1);
783 if (left != NULL) {
784 if (slen > 0) memcpy(left, e, slen);
785 processMiscCmds(cmdname, left);
786 free(left);
790 return 0;
795 static const char *cmdpSkipStr (const char *str) {
796 while (*str && isspace(*str)) ++str;
797 if (str[0] && str[0] != ';') {
798 char qch = ' ';
800 while (*str) {
801 if (*str == ';' && qch == ' ') break;
802 if (qch != ' ' && *str == qch) { qch = ' '; ++str; continue; }
803 if (*str == '"' || *str == '\'') {
804 if (qch == ' ') qch = *str;
805 ++str;
806 continue;
808 if (*str++ == '\\' && *str) ++str;
811 return str;
816 static void executeCommands (const char *str) {
817 oldTerm = curterm;
818 oldTermIdx = termidx;
819 newTerm = NULL;
820 newTermSwitch = 0;
821 if (str == NULL) return;
822 while (*str) {
823 const char *ce;
824 char qch;
826 while (*str && isspace(*str)) ++str;
827 if (!*str) break;
828 if (*str == ';') { ++str; continue; }
830 ce = str;
831 qch = ' ';
832 while (*ce) {
833 if (*ce == ';' && qch == ' ') break;
834 if (qch != ' ' && *ce == qch) { qch = ' '; ++ce; continue; }
835 if (*ce == '"' || *ce == '\'') {
836 if (qch == ' ') qch = *ce;
837 ++ce;
838 continue;
840 if (*ce++ == '\\' && *ce) ++ce;
843 if (executeCommand(str, ce-str)) break;
844 if (*ce) str = ce+1; else break;
846 flushNewTerm();
847 switchToTerm(oldTermIdx, 1);