fixed "-e" command (it should use all following args); some cosmetic fixes
[k8sterm.git] / src / commands.c
blobd4bd5a309f94fe9304371d5f1353ea618fe702d4
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 cmdHideSelection (const char *cmdname, char *argstr) {
36 k8t_selHide(curterm);
40 static void cmdExec (const char *cmdname, char *argstr) {
41 if (curterm != NULL) {
42 if (K8T_DATA(curterm)->execcmd != NULL) free(K8T_DATA(curterm)->execcmd);
43 K8T_DATA(curterm)->execcmd = (argstr[0] ? strdup(argstr) : NULL);
48 static int parseTabArgs (char *argstr, int *noswitch, int nowrap, int idx) {
49 for (;;) {
50 char *arg;
52 while (*argstr && isspace(*argstr)) ++argstr;
53 if (!argstr[0]) break;
54 if (iniParseArguments(argstr, "s-R-", &arg, &argstr) != NULL) break;
56 if (strcasecmp(arg, "noswitch") == 0) *noswitch = 1;
57 else if (strcasecmp(arg, "switch") == 0) *noswitch = 0;
58 else if (strcasecmp(arg, "nowrap") == 0) nowrap = 1;
59 else if (strcasecmp(arg, "wrap") == 0) nowrap = 0;
60 else if (strcasecmp(arg, "first") == 0) idx = 0;
61 else if (strcasecmp(arg, "last") == 0) idx = term_count-1;
62 else if (strcasecmp(arg, "prev") == 0) idx = -1;
63 else if (strcasecmp(arg, "next") == 0) idx = -2;
64 else {
65 long int n = -1;
66 char *eptr;
68 n = strtol(arg, &eptr, 0);
69 if (!eptr[0] && n >= 0 && n < term_count) idx = n;
72 switch (idx) {
73 case -1: // prev
74 if ((idx = termidx-1) < 0) idx = nowrap ? 0 : term_count-1;
75 break;
76 case -2: // next
77 if ((idx = termidx+1) >= term_count) idx = nowrap ? term_count-1 : 0;
78 break;
80 return idx;
84 static void flushNewTerm (void) {
85 if (newTerm != NULL) {
86 if (newTermSwitch && curterm != NULL) curterm->lastActiveTime = mclock_ticks();
87 //curterm = newTerm;
88 //termidx = newTermIdx;
89 k8t_tmInitialize(newTerm, term_array[0]->col, term_array[0]->row, opt_maxhistory);
90 //termCreateXPixmap(newTerm);
91 //newTerm->drawSetFG(newTerm, newTerm->defbg);
92 k8t_tmClearRegion(newTerm, 0, 0, newTerm->col-1, newTerm->row-1);
93 k8t_tmFullDirty(newTerm);
95 if (k8t_ttyNew(newTerm) != 0) {
96 curterm = oldTerm;
97 termidx = oldTermIdx;
98 termfree(newTermIdx);
99 } else {
100 k8t_selInit(newTerm);
101 k8t_ttyResize(newTerm);
102 if (newTermSwitch) {
103 curterm = NULL;
104 termidx = 0;
105 switchToTerm(newTermIdx, 1);
106 oldTerm = curterm;
107 oldTermIdx = termidx;
108 } else {
109 curterm = oldTerm;
110 termidx = oldTermIdx;
113 newTerm = NULL;
118 static void cmdNewTab (const char *cmdname, char *argstr) {
119 int noswitch = 0, idx;
121 if (opt_disabletabs) return;
122 flushNewTerm();
123 if ((newTerm = k8t_termalloc()) == NULL) return;
124 k8t_tmInitialize(newTerm, term_array[0]->col, term_array[0]->row, opt_maxhistory);
125 /*idx =*/ parseTabArgs(argstr, &noswitch, 0, termidx);
126 idx = term_count-1;
127 if (!noswitch) {
128 if (curterm != NULL) curterm->lastActiveTime = mclock_ticks();
129 oldTermIdx = idx;
131 newTermIdx = termidx = idx;
132 curterm = newTerm;
133 newTermSwitch = !noswitch;
137 static void cmdCloseTab (const char *cmdname, char *argstr) {
138 flushNewTerm();
139 if (curterm != NULL && !curterm->dead) kill(K8T_DATA(curterm)->pid, SIGTERM);
143 static void cmdKillTab (const char *cmdname, char *argstr) {
144 flushNewTerm();
145 if (!curterm->dead) kill(K8T_DATA(curterm)->pid, SIGKILL);
149 static void cmdSwitchToTab (const char *cmdname, char *argstr) {
150 int noswitch = 0, idx;
152 flushNewTerm();
153 idx = parseTabArgs(argstr, &noswitch, 0, -666);
154 if (idx >= 0) {
155 switchToTerm(idx, 1);
156 oldTerm = curterm;
157 oldTermIdx = termidx;
162 static void cmdMoveTabTo (const char *cmdname, char *argstr) {
163 int noswitch = 0, idx;
165 flushNewTerm();
166 idx = parseTabArgs(argstr, &noswitch, 0, termidx);
167 if (idx != termidx && idx >= 0 && idx < term_count) {
168 K8Term *t = term_array[termidx];
170 // remove current term
171 for (int f = termidx+1; f < term_count; ++f) term_array[f-1] = term_array[f];
172 // insert term
173 for (int f = term_count-2; f >= idx; --f) term_array[f+1] = term_array[f];
174 term_array[idx] = t;
175 termidx = idx;
176 oldTerm = t;
177 oldTermIdx = idx;
178 fixFirstTab();
179 updateTabBar = 1;
184 static void cmdDefaultFG (const char *cmdname, char *argstr) {
185 char *s = NULL;
186 int c;
188 if (iniParseArguments(argstr, "i{0,511}|s-", &c, &s) == NULL) {
189 if (s != NULL && tolower(s[0]) == 'g') defaultFG = c; else curterm->deffg = c;
194 static void cmdDefaultBG (const char *cmdname, char *argstr) {
195 char *s = NULL;
196 int c;
198 if (iniParseArguments(argstr, "i{0,511}|s-", &c) == NULL) {
199 if (s != NULL && tolower(s[0]) == 'g') {
200 defaultBG = c;
201 } else {
202 curterm->defbg = c;
203 XSetWindowBackground(xw.dpy, xw.win, getColor(curterm->defbg));
204 if (newTerm == NULL) {
205 k8t_tmFullDirty(curterm);
206 k8t_drawTerm(curterm, 1);
207 xclearunused();
214 static void scrollHistory (K8Term *term, int delta) {
215 if (term == NULL || term->maxhistory < 1) return; // no history
216 term->topline += delta;
217 if (term->topline > term->maxhistory) term->topline = term->maxhistory;
218 if (term->topline < 0) term->topline = 0;
219 k8t_tmFullDirty(term);
220 k8t_drawTerm(term, 1);
224 static void cmdScrollHistoryLineUp (const char *cmdname, char *argstr) {
225 scrollHistory(curterm, 1);
229 static void cmdScrollHistoryPageUp (const char *cmdname, char *argstr) {
230 scrollHistory(curterm, curterm->row);
234 static void cmdScrollHistoryLineDown (const char *cmdname, char *argstr) {
235 scrollHistory(curterm, -1);
239 static void cmdScrollHistoryPageDown (const char *cmdname, char *argstr) {
240 scrollHistory(curterm, -curterm->row);
244 static void cmdScrollHistoryTop (const char *cmdname, char *argstr) {
245 scrollHistory(curterm, curterm->linecount);
249 static void cmdScrollHistoryBottom (const char *cmdname, char *argstr) {
250 scrollHistory(curterm, -curterm->linecount);
254 static void cmdCommandMode (const char *cmdname, char *argstr) {
255 if (curterm != NULL) {
256 if (CMDLD(curterm).cmdMode == K8T_CMDMODE_NONE) tcmdlineinit(curterm, &CMDLD(curterm)); else tcmdlinehide(curterm, &CMDLD(curterm));
261 // [show|hide]
262 static void cmdCursor (const char *cmdname, char *argstr) {
263 if (curterm != NULL) {
264 char *s;
266 if (iniParseArguments(argstr, "s!-", &s) != NULL) {
267 tcmdlinemsgf(curterm, &CMDLD(curterm), "cursor is %s", ((curterm->c.state&K8T_CURSOR_HIDE) ? "hidden" : "visible"));
268 } else {
269 if (strcasecmp(s, "show") == 0) curterm->c.state &= ~K8T_CURSOR_HIDE;
270 else if (strcasecmp(s, "hide") == 0) curterm->c.state |= K8T_CURSOR_HIDE;
271 k8t_tmWantRedraw(curterm, 0);
277 static void cmdReset (const char *cmdname, char *argstr) {
278 char *s = NULL;
280 if (curterm != NULL) {
281 if (iniParseArguments(argstr, "|s-", &s) == NULL) {
282 if (s != NULL) {
283 switch (tolower(s[0])) {
284 case 'a': // all
285 k8t_tmResetMode(curterm);
286 return;
287 case 'c': // colors
288 k8t_tmResetAttrs(curterm);
289 return;
290 case 'g': // graphics
291 curterm->mode &= ~(K8T_MODE_GFX0|K8T_MODE_GFX1);
292 curterm->charset = K8T_MODE_GFX0;
293 return;
294 case 'u': // cursor
295 curterm->csaved.state = curterm->c.state = K8T_CURSOR_DEFAULT;
296 return;
300 tcmdlinemsgf(curterm, &CMDLD(curterm), "Reset (a)ll | (c)olor | (g)raphics | c(u)rsor");
305 // [norm|alt]
306 static void cmdScreen (const char *cmdname, char *argstr) {
307 if (curterm != NULL) {
308 char *s;
310 if (iniParseArguments(argstr, "s!-", &s) != NULL) {
311 tcmdlinemsgf(curterm, &CMDLD(curterm), "screen: %s", (K8T_ISSET(curterm, K8T_MODE_ALTSCREEN) ? "alt" : "norm"));
312 } else {
313 if (strcasecmp(s, "norm") == 0) {
314 if (K8T_ISSET(curterm, K8T_MODE_ALTSCREEN)) k8t_tmSwapScreen(curterm);
315 } else if (strcasecmp(s, "alt") == 0) {
316 if (!K8T_ISSET(curterm, K8T_MODE_ALTSCREEN)) k8t_tmSwapScreen(curterm);
323 // [on|off]
324 static void cmdMouseReports (const char *cmdname, char *argstr) {
325 if (curterm != NULL) {
326 int b;
328 if (iniParseArguments(argstr, "b", &b) != NULL) {
329 tcmdlinemsgf(curterm, &CMDLD(curterm), "mouse reports are o%s", (K8T_ISSET(curterm, K8T_MODE_MOUSE) ? "n" : "ff"));
330 } else {
331 if (b) curterm->mode |= K8T_MODE_MOUSEBTN; else curterm->mode &= ~K8T_MODE_MOUSEBTN;
337 static int cmd_parseIntArg (const char *fmt, char *argstr, int *b, int *global, int *toggle) {
338 while (argstr[0]) {
339 char *s = NULL;
341 if (iniParseArguments(argstr, "R-", &argstr) != NULL) break;
342 if (!argstr[0]) break;
344 if (iniParseArguments(argstr, "s!-R-", &s, &argstr) != NULL) break;
345 if (global && tolower(s[0]) == 'g') {
346 *global = 1;
347 } else if (toggle && tolower(s[0]) == 't') {
348 *toggle = 1;
349 } else {
350 if (!b || iniParseArguments(s, fmt, b) != NULL) return -1;
353 return 0;
357 static void cmdUTF8Locale (const char *cmdname, char *argstr) {
358 int b = -1, toggle = 0;
360 if (cmd_parseIntArg("b", argstr, &b, NULL, &toggle) != 0) return;
361 if (b == -1) {
362 tcmdlinemsgf(curterm, &CMDLD(curterm), "UTF8Locale: %s", ((needConversion ? !curterm->needConv : 1) ? "yes" : "no"));
363 } else {
364 if (!needConversion) b = 1;
365 if (curterm != NULL) curterm->needConv = !b;
370 static void cmdAudibleBell (const char *cmdname, char *argstr) {
371 int b = -1, toggle = 0, global = 0;
373 if (curterm == NULL) return;
374 if (cmd_parseIntArg("b", argstr, &b, &global, &toggle) != 0) return;
376 if (b == -1) {
377 tcmdlinemsgf(curterm, &CMDLD(curterm), "AudibleBell: %s", (global ? opt_audiblebell : (curterm->belltype&K8T_BELL_AUDIO)) ? "yes" : "no");
378 } else {
379 if (toggle) {
380 if (global) opt_audiblebell = !opt_audiblebell; else curterm->belltype ^= K8T_BELL_AUDIO;
381 } else {
382 if (global) opt_audiblebell = b; else curterm->belltype = (curterm->belltype&~K8T_BELL_AUDIO)|(b!=0?K8T_BELL_AUDIO:0);
388 static void cmdUrgentBell (const char *cmdname, char *argstr) {
389 int b = -1, toggle = 0, global = 0;
391 if (curterm == NULL) return;
392 if (cmd_parseIntArg("b", argstr, &b, &global, &toggle) != 0) return;
394 if (b == -1) {
395 tcmdlinemsgf(curterm, &CMDLD(curterm), "UrgentBell: %s", (global ? opt_urgentbell : (curterm->belltype&K8T_BELL_URGENT)) ? "yes" : "no");
396 } else {
397 if (toggle) {
398 if (global) opt_urgentbell = !opt_urgentbell; else curterm->belltype ^= K8T_BELL_URGENT;
399 } else {
400 if (global) opt_urgentbell = b; else curterm->belltype = (curterm->belltype&~K8T_BELL_URGENT)|(b!=0?K8T_BELL_URGENT:0);
406 static void cmdMonochrome (const char *cmdname, char *argstr) {
407 int b = -1, global = 0;
409 if (curterm == NULL) return;
410 if (cmd_parseIntArg("i{0,3}", argstr, &b, &global, NULL) != 0) return;
412 if (b == -1) {
413 b = (global ? globalBW : curterm->blackandwhite);
414 tcmdlinemsgf(curterm, &CMDLD(curterm), "Monochrome: %d", b);
415 } else {
416 if (global) {
417 if (b == 3) tcmdlinemsg(curterm, &CMDLD(curterm), "Monochrome-global can't be '3'!");
418 else globalBW = b;
419 } else {
420 curterm->blackandwhite = b;
423 k8t_tmFullDirty(curterm);
424 updateTabBar = 1;
428 static void cmdCursorBlink (const char *cmdname, char *argstr) {
429 int b = -1, global = 0;
431 if (curterm == NULL) return;
432 if (cmd_parseIntArg("i{0,10000}", argstr, &b, &global, NULL) != 0) return;
434 if (b == -1) {
435 b = (global ? opt_cursorBlink : curterm->curblink);
436 tcmdlinemsgf(curterm, &CMDLD(curterm), "CursorBlink: %d", b);
437 } else {
438 if (global) {
439 opt_cursorBlink = b;
440 } else {
441 curterm->curblink = b;
442 curterm->curbhidden = 0;
445 k8t_tmFullDirty(curterm);
446 updateTabBar = 1;
450 static void cmdCursorBlinkInactive (const char *cmdname, char *argstr) {
451 int b = -1, global = 0, toggle = 0, *iptr;
453 if (curterm == NULL) return;
454 if (cmd_parseIntArg("b", argstr, &b, &global, &toggle) != 0) return;
456 iptr = (global ? &opt_cursorBlinkInactive : &curterm->curblinkinactive);
457 if (b != -1) {
458 if (toggle) *iptr = !(*iptr); else *iptr = b;
459 k8t_drawTerm(curterm, 0);
464 static void cmdIgnoreClose (const char *cmdname, char *argstr) {
465 int b = -666;
467 if (curterm == NULL) return;
468 if (cmd_parseIntArg("i{-1,1}", argstr, &b, NULL, NULL) != 0) return;
470 if (b == -666) {
471 tcmdlinemsgf(curterm, &CMDLD(curterm), "IgnoreClose: %d", opt_ignoreclose);
472 } else {
473 opt_ignoreclose = b;
478 static void cmdMaxHistory (const char *cmdname, char *argstr) {
479 int b = -1, global = 0;
481 if (curterm == NULL) return;
482 if (cmd_parseIntArg("i{0,65535}", argstr, &b, &global, NULL) != 0) return;
484 if (b == -1) {
485 tcmdlinemsgf(curterm, &CMDLD(curterm), "MaxHistory: %d", (global?opt_maxhistory:curterm->maxhistory));
486 } else {
487 if (!global) k8t_tmAdjMaxHistory(curterm, b); else opt_maxhistory = b;
492 static void cmdMaxDrawTimeout (const char *cmdname, char *argstr) {
493 int b = -1;
495 if (curterm == NULL) return;
496 if (cmd_parseIntArg("i{100,60000}", argstr, &b, NULL, NULL) != 0) return;
498 if (b == -1) {
499 tcmdlinemsgf(curterm, &CMDLD(curterm), "MaxDrawTimeout: %d", opt_maxdrawtimeout);
500 } else {
501 opt_maxdrawtimeout = b;
506 static void cmdSwapDrawTimeout (const char *cmdname, char *argstr) {
507 int b = -1;
509 if (curterm == NULL) return;
510 if (cmd_parseIntArg("i{10,60000}", argstr, &b, NULL, NULL) != 0) return;
512 if (b == -1) {
513 tcmdlinemsgf(curterm, &CMDLD(curterm), "SwapDrawTimeout: %d", opt_swapdrawtimeout);
514 } else {
515 opt_swapdrawtimeout = b;
520 static void cmdDrawTimeout (const char *cmdname, char *argstr) {
521 int b = -1;
523 if (curterm == NULL) return;
524 if (cmd_parseIntArg("i{5,30000}", argstr, &b, NULL, NULL) != 0) return;
526 if (b == -1) {
527 tcmdlinemsgf(curterm, &CMDLD(curterm), "DrawTimeout: %d", opt_drawtimeout);
528 } else {
529 opt_drawtimeout = b;
534 static void cmdTabPosition (const char *cmdname, char *argstr) {
535 int newpos = -1;
537 while (argstr[0]) {
538 char *s = NULL;
540 if (iniParseArguments(argstr, "R-", &argstr) != NULL) break;
541 if (!argstr[0]) break;
543 if (iniParseArguments(argstr, "s!-R-", &s, &argstr) != NULL) break;
544 if (tolower(s[0]) == 't') newpos = 1;
545 else if (tolower(s[0]) == 'b') newpos = 0;
546 else if (iniParseArguments(s, "i{0,1}", &newpos) != NULL) return;
549 if (newpos == -1) {
550 tcmdlinemsgf(curterm, &CMDLD(curterm), "TabPostion: %s", (opt_tabposition == 0 ? "bottom" : "top"));
551 } else if (opt_tabposition != newpos) {
552 opt_tabposition = newpos;
553 updateTabBar = 1;
554 k8t_tmFullDirty(curterm);
555 k8t_drawTerm(curterm, 1);
556 xdrawTabBar();
557 xclearunused();
562 static void cmdTabCount (const char *cmdname, char *argstr) {
563 int b = -1;
565 if (curterm == NULL) return;
566 if (cmd_parseIntArg("i{1,128}", argstr, &b, NULL, NULL) != 0) return;
568 if (b == -1) {
569 tcmdlinemsgf(curterm, &CMDLD(curterm), "TabCount: %d", opt_tabcount);
570 } else if (opt_tabcount != b) {
571 opt_tabcount = b;
572 fixFirstTab();
573 updateTabBar = 1;
574 xdrawTabBar();
579 static void cmdDoFullRedraw (const char *cmdname, char *argstr) {
580 updateTabBar = 1;
581 k8t_tmFullDirty(curterm);
582 xclearunused();
583 k8t_drawTerm(curterm, 1);
584 xdrawTabBar();
588 static void cmdTitle (const char *cmdname, char *argstr) {
589 if (curterm != NULL) {
590 char *s = NULL;
592 if (iniParseArguments(argstr, "s-", &s) != NULL || s == NULL) return;
593 memset(curterm->title, 0, sizeof(curterm->title));
594 while (strlen(s) > K8T_ESC_TITLE_SIZ) k8t_UTF8ChopLast(s);
595 fprintf(stderr, "[%s]\n", s);
596 strncpy(curterm->title, s, K8T_ESC_TITLE_SIZ);
597 fixWindowTitle(curterm);
598 updateTabBar = 1;
599 xdrawTabBar();
604 static void cmdFastRedraw (const char *cmdname, char *argstr) {
605 int b = -1, global = 0, toggle = 0, *iptr;
607 if (curterm == NULL) return;
608 if (cmd_parseIntArg("b", argstr, &b, &global, &toggle) != 0) return;
610 iptr = (global ? &opt_fastredraw : &curterm->fastredraw);
611 if (b != -1) {
612 if (toggle) *iptr = !(*iptr); else *iptr = b;
613 k8t_drawTerm(curterm, 0);
614 } else {
615 tcmdlinemsgf(curterm, &CMDLD(curterm), "FastRedraw: %s", (*iptr ? "yes" : "no"));
620 static void cmdFastUpdate (const char *cmdname, char *argstr) {
621 int b = -1, toggle = 0, *iptr;
623 if (curterm == NULL) return;
624 if (cmd_parseIntArg("b", argstr, &b, NULL, &toggle) != 0) return; // only global
626 iptr = &opt_fastupdate;
627 if (b != -1) {
628 if (toggle) *iptr = !(*iptr); else *iptr = b;
629 k8t_drawTerm(curterm, 0);
630 } else {
631 tcmdlinemsgf(curterm, &CMDLD(curterm), "FastUpdate: %s", (*iptr ? "yes" : "no"));
636 static void cmdScrollClear (const char *cmdname, char *argstr) {
637 int b = -666, global = 0, *iptr;
639 if (curterm == NULL) return;
640 if (cmd_parseIntArg("i{-1,2}", argstr, &b, &global, NULL) != 0) return;
642 iptr = (global ? &opt_scrollclear : &curterm->clearOnPartialScrollMode);
643 if (b == -666) {
644 tcmdlinemsgf(curterm, &CMDLD(curterm), "ScrollClear: %d", *iptr);
645 } else if (b != -666) {
646 *iptr = b;
651 static void cmdAbout (const char *cmdname, char *argstr) {
652 if (curterm != NULL) {
653 tcmdlinemsgf(curterm, &CMDLD(curterm), "k8sterm " VERSION);
658 static void cmdDebugDump (const char *cmdname, char *argstr) {
659 if (curterm != NULL) {
660 char *s = NULL;
662 if (iniParseArguments(argstr, "s-", &s) == NULL) {
663 if (s != NULL) {
664 switch (tolower(s[0])) {
665 case 'o': // off
666 case 'n': // none
667 curterm->dumpescapes = 0;
668 curterm->dumpeskeys = 0;
669 return;
670 case 'a': // all
671 curterm->dumpescapes = 1;
672 curterm->dumpeskeys = 1;
673 return;
674 case 'e': // escapes
675 curterm->dumpescapes = !curterm->dumpescapes;
676 return;
677 case 'k': // keys
678 curterm->dumpeskeys = !curterm->dumpeskeys;
679 return;
683 tcmdlinemsgf(curterm, &CMDLD(curterm), "DbgDump (n)one | (a)ll | toggle (e)scapes | toggle extended (k)eys");
688 // 0: none
689 // 1: in center
690 // 2: at left
691 // 3: at right
692 static void cmdTabEllipsis (const char *cmdname, char *argstr) {
693 int b = -1;
695 if (curterm == NULL) return;
696 if (cmd_parseIntArg("i{0,3}", argstr, &b, NULL, NULL) != 0) return;
698 if (b != -1) {
699 if (opt_tabellipsis != b) {
700 opt_tabellipsis = b;
701 updateTabBar = 1;
702 xdrawTabBar();
704 } else {
705 tcmdlinemsgf(curterm, &CMDLD(curterm), "TabEllipsis: %d", opt_tabellipsis);
710 static const Command commandList[] = {
711 {"PastePrimary", cmdPastePrimary},
712 {"PasteSecondary", cmdPasteSecondary},
713 {"PasteClipboard", cmdPasteClipboard},
714 {"HideSelection", cmdHideSelection},
715 {"exec", cmdExec},
716 {"NewTab", cmdNewTab}, // 'noswitch' 'next' 'prev' 'first' 'last'
717 {"CloseTab", cmdCloseTab},
718 {"KillTab", cmdKillTab},
719 {"SwitchToTab", cmdSwitchToTab}, // 'next' 'prev' 'first' 'last' 'nowrap' 'wrap'
720 {"MoveTabTo", cmdMoveTabTo}, // 'next' 'prev' 'first' 'last' 'nowrap' 'wrap'
721 {"DefaultFG", cmdDefaultFG},
722 {"DefaultBG", cmdDefaultBG},
723 {"ScrollHistoryLineUp", cmdScrollHistoryLineUp},
724 {"ScrollHistoryPageUp", cmdScrollHistoryPageUp},
725 {"ScrollHistoryLineDown", cmdScrollHistoryLineDown},
726 {"ScrollHistoryPageDown", cmdScrollHistoryPageDown},
727 {"ScrollHistoryTop", cmdScrollHistoryTop},
728 {"ScrollHistoryBottom", cmdScrollHistoryBottom},
729 {"UTF8Locale", cmdUTF8Locale}, // 'on', 'off'
730 {"AudibleBell", cmdAudibleBell},
731 {"UrgentBell", cmdUrgentBell},
732 {"CommandMode", cmdCommandMode},
733 {"Cursor", cmdCursor},
734 {"Reset", cmdReset},
735 {"Screen", cmdScreen},
736 {"MouseReports", cmdMouseReports},
737 {"Monochrome", cmdMonochrome},
738 {"Mono", cmdMonochrome},
739 {"CursorBlink", cmdCursorBlink},
740 {"CursorBlinkInactive", cmdCursorBlinkInactive},
741 {"IgnoreClose", cmdIgnoreClose},
742 {"MaxHistory", cmdMaxHistory},
743 {"MaxDrawTimeout", cmdMaxDrawTimeout},
744 {"SwapDrawTimeout", cmdSwapDrawTimeout},
745 {"DrawTimeout", cmdDrawTimeout},
746 {"TabPosition", cmdTabPosition},
747 {"TabCount", cmdTabCount},
748 {"DoFullRedraw", cmdDoFullRedraw},
749 {"Title", cmdTitle},
750 {"FastRedraw", cmdFastRedraw},
751 {"FastUpdate", cmdFastUpdate},
752 {"ScrollClear", cmdScrollClear},
753 {"TabEllipsis", cmdTabEllipsis},
755 {"KeyBind", NULL},
756 {"KeyTrans", NULL},
757 {"KeyMap", NULL},
758 {"UniMap", NULL},
760 {"DbgDump", cmdDebugDump},
762 {"About", cmdAbout},
764 {"term", cmdTermName},
765 {"title", cmdWinTitle},
766 {"tabsize", cmdTabSize},
767 {"defaultcursorfg", cmdDefaultCursorFG},
768 {"defaultcursorbg", cmdDefaultCursorBG},
769 {"defaultinactivecursorfg", cmdDefaultInactiveCursorFG},
770 {"defaultinactivecursorbg", cmdDefaultInactiveCursorBG},
771 {"defaultboldfg", cmdDefaultBoldFG},
772 {"defaultunderlinefg", cmdDefaultUnderlineFG},
774 {NULL, NULL}
778 static const char *findCommandCompletion (const char *str, int slen, const char *prev) {
779 const char *res = NULL;
780 int phit = 0;
782 if (slen < 1) return NULL;
783 for (int f = 0; commandList[f].name != NULL; ++f) {
784 if (strlen(commandList[f].name) >= slen && strncasecmp(commandList[f].name, str, slen) == 0) {
785 if (prev == NULL || phit) return commandList[f].name;
786 if (strcasecmp(commandList[f].name, prev) == 0) phit = 1;
787 if (res == NULL) res = commandList[f].name;
790 return res;
794 // !0: NewTab command
795 static int executeCommand (const char *str, int slen) {
796 const char *e;
797 char *cmdname;
798 int cmdfound = 0;
800 if (str == NULL) return 0;
801 if (slen < 0) slen = strlen(str);
803 for (int f = 0; f < slen; ++f) if (!str[f]) { slen = f; break; }
805 while (slen > 0 && isspace(*str)) { ++str; --slen; }
806 if (slen < 1 || !str[0]) return 0;
808 for (e = str; slen > 0 && !isspace(*e); ++e, --slen) ;
810 if (e-str > 127) return 0;
811 cmdname = alloca(e-str+8);
812 if (cmdname == NULL) return 0;
813 memcpy(cmdname, str, e-str);
814 cmdname[e-str] = 0;
815 if (opt_disabletabs && strcasecmp(cmdname, "NewTab") == 0) return 1;
817 while (slen > 0 && isspace(*e)) { ++e; --slen; }
818 //FIXME: ugly copypaste!
820 for (int f = 0; commandList[f].name != NULL; ++f) {
821 if (strcasecmp(commandList[f].name, cmdname) == 0 && commandList[f].fn != NULL) {
822 char *left = calloc(slen+2, 1);
824 if (left != NULL) {
825 if (slen > 0) memcpy(left, e, slen);
826 //fprintf(stderr, "command: [%s]; args: [%s]\n", cmdname, left);
827 commandList[f].fn(cmdname, left);
828 free(left);
830 cmdfound = 1;
831 break;
835 if (!cmdfound) {
836 char *left = calloc(slen+2, 1);
838 if (left != NULL) {
839 if (slen > 0) memcpy(left, e, slen);
840 processMiscCmds(cmdname, left);
841 free(left);
845 return 0;
850 static const char *cmdpSkipStr (const char *str) {
851 while (*str && isspace(*str)) ++str;
852 if (str[0] && str[0] != ';') {
853 char qch = ' ';
855 while (*str) {
856 if (*str == ';' && qch == ' ') break;
857 if (qch != ' ' && *str == qch) { qch = ' '; ++str; continue; }
858 if (*str == '"' || *str == '\'') {
859 if (qch == ' ') qch = *str;
860 ++str;
861 continue;
863 if (*str++ == '\\' && *str) ++str;
866 return str;
871 static void executeCommands (const char *str) {
872 oldTerm = curterm;
873 oldTermIdx = termidx;
874 newTerm = NULL;
875 newTermSwitch = 0;
876 if (str == NULL) return;
877 while (*str) {
878 const char *ce;
879 char qch;
881 while (*str && isspace(*str)) ++str;
882 if (!*str) break;
883 if (*str == ';') { ++str; continue; }
885 ce = str;
886 qch = ' ';
887 while (*ce) {
888 if (*ce == ';' && qch == ' ') break;
889 if (qch != ' ' && *ce == qch) { qch = ' '; ++ce; continue; }
890 if (*ce == '"' || *ce == '\'') {
891 if (qch == ' ') qch = *ce;
892 ++ce;
893 continue;
895 if (*ce++ == '\\' && *ce) ++ce;
898 if (executeCommand(str, ce-str)) break;
899 if (*ce) str = ce+1; else break;
901 flushNewTerm();
902 switchToTerm(oldTermIdx, 1);