Corrected compiler error
[rofl0r-motor.git] / src / ui / ncurses / ncursesui.cc
blob9fa72ed12128dfded7df5a6592e161ec8f8d0d40
1 #include "ncursesui.h"
2 #include "motormanager.h"
3 #include "motordebugger.h"
4 #include "motorconfiguration.h"
5 #include "motormisc.h"
6 #include "motorvcs.h"
8 #include "uieditor.h"
9 #include "uigrepper.h"
10 #include "uiwatcher.h"
11 #include "uiregexper.h"
12 #include "uivcs.h"
14 #include "kkfsys.h"
16 #include <sstream>
17 #include <iostream>
19 #include <sys/wait.h>
21 ncursesui thisui;
23 #define LOOKER_HEIGHT (LINES-2)
24 #define OUTLINES_LIMIT 512
25 #define NULL_CONST_STR ((const char *) 0)
27 #define getcolor(c) uiconf.getcolor(c)
29 ncursesui::ncursesui(): terminate(false), outopen(false) {
32 ncursesui::~ncursesui() {
33 if(terminate) {
34 kendinterface();
35 for(INT i = 0; i < LINES; i++) cout << endl;
39 void ncursesui::sighandler(int signum) {
40 switch(signum) {
41 case SIGCHLD:
42 while(wait3(0, WNOHANG, 0) > 0);
43 break;
46 signal(SIGCHLD, &sighandler);
47 signal(SIGINT, &sighandler);
50 void ncursesui::execute(INT argc, char **argv) {
51 string pname;
53 kinterface();
54 uiconf.load();
55 ed.loadsettings();
57 sighandler(0);
59 commandline(argc, argv);
60 outwindow = textwindow(0, 1, COLS, LOOKER_HEIGHT, normalcolor(0), TW_SPACEBORDER);
61 workareaupdate();
62 initelements();
63 log();
65 if(project.empty()) pload();
67 if(!project.empty()) {
68 initmenubar();
70 do {
71 mainloop();
72 terminate = project.close();
73 } while(!terminate);
76 uiconf.save();
79 void ncursesui::pload(const projectname pname) {
80 projectname nname = pname;
81 motorproject np;
82 bool fin;
84 for(fin = false; !fin; ) {
85 if(nname.empty()) {
86 nname = selectproject(selectorcreate);
89 if(!(fin = nname.empty())) {
90 np = motorproject(nname);
92 if(!np.empty())
93 if(project.close()) {
94 project = motorproject(static_cast<projectname> (np));
95 onprojectload();
96 fin = true;
100 nname = projectname();
103 terminate = project.empty();
106 motorui::askresult ncursesui::ask(const string &answersallowed, const string &text) {
107 INT line = /*watcher.visible() ? LINES-uiconf.getwatchlines()-2 :*/ LINES-2;
108 screenarea sarea(0, line, COLS, line);
109 string msg;
110 string::const_iterator c;
111 INT key;
113 attrset(getcolor(cp_input));
114 mvhline(line, 0, ' ', COLS);
116 msg = text + " (";
117 for(c = answersallowed.begin(); c != answersallowed.end(); c++) {
118 msg += c != answersallowed.begin() ? tolower(*c) : toupper(*c);
119 if(c != answersallowed.end()-1) msg += '/';
122 msg += ") ";
123 kwriteat(0, line, msg.c_str(), getcolor(cp_input));
125 while(1) {
126 key = toupper(getch());
127 if(key == '\r') key = toupper(*answersallowed.begin());
128 if(answersallowed.find(key) != -1) break;
131 sarea.restore();
133 switch(key) {
134 case 'Y': return motorui::yes;
135 case 'C': return motorui::cancel;
136 case 'A': return motorui::all;
137 case 'N': return motorui::no;
140 return motorui::no;
143 void ncursesui::log(const string &text) {
144 bool hl = false;
145 string::const_iterator i;
147 attrset(getcolor(cp_bottom));
148 mvhline(LINES-1, 0, ' ', COLS);
149 mvprintw(LINES-1, 0, "");
151 for(i = text.begin(); i != text.end(); i++) {
152 if(*i == '~') {
153 if(text.substr(i-text.begin(), 2) != "~~") {
154 if(hl = !hl) {
155 attrset(getcolor(cp_bottomhl));
156 } else {
157 attrset(getcolor(cp_bottom));
159 } else {
160 printw("~");
161 i++;
163 } else {
164 printw("%c", *i);
168 refresh();
171 void ncursesui::loadeditfile(const motorui::editfile ef, INT options) {
172 ifstream f;
173 INT i;
174 char buf[512];
175 string fname;
176 bool found;
177 vector<motorfolder>::iterator ifold, icfold;
178 vector<motorfile>::iterator ifile, icfile;
179 motorproject pf;
181 if(ef.fname.empty()) return;
183 if((fname = ef.fname).substr(0, 1) != "/") {
184 fname = (string) getcwd(buf, 512) + "/" + fname;
187 if(access(fname.c_str(), F_OK)) {
188 fname = justfname(fname);
190 for(ifold = project.foldbegin(), found = false; !found && ifold != project.foldend(); ifold++)
191 for(ifile = ifold->begin(); !found && ifile != ifold->end(); ifile++)
192 switch(ifold->getcontentkind()) {
193 case motorfile::source:
194 if(found = (justfname(ifile->getfname()) == fname))
195 fname = project.transformfname(projectpaths::absolute, ifile->getfname());
196 break;
198 case motorfile::project:
199 pf = motorproject(ifile->getfname());
201 for(icfold = pf.foldbegin(); !found && icfold != pf.foldend(); icfold++) {
202 if(icfold->getcontentkind() == motorfile::source) {
203 for(icfile = icfold->begin(); !found && icfile != icfold->end(); icfile++) {
204 if(found = (justfname(icfile->getfname()) == fname))
205 fname = pf.transformfname(projectpaths::absolute,
206 icfile->getfname());
210 break;
214 for(i = 0, found = false; i < ed.getfcount() && !found; i++) {
215 found = samefile(ed.getfid(i), fname);
218 if(found) {
219 ed.setfnum(i-1);
220 } else {
221 if((options & LF_CREATE_IF_NOTFOUND) && access(fname.c_str(), F_OK)) {
222 ed.load("", fname);
223 } else {
224 f.open(fname.c_str());
225 if(f.is_open()) {
226 ed.load(f, fname);
227 ed.markbreakpoints();
228 f.close();
233 if(ef.x != -1 && ef.y != -1)
234 ed.setpos(ef.x, ef.y-1);
236 statusupdate();
239 void ncursesui::commandline(INT argc, char **argv) {
240 INT r;
241 string slong;
243 for(r = 1; argv[r]; r++) {
244 slong = argv[r];
246 if(slong == "--ascii" || slong == "-a") {
247 kintf_graph = 0;
249 } else if((slong == "--debugtty" || slong == "-t") && argv[++r]) {
250 debugger.forceusetty(argv[r]);
252 } else if(slong == "--help" || slong.substr(0, 1) == "-") {
253 usage();
254 exit(0);
256 } else if(project.empty()) {
257 project = motorproject(projectname(slong));
258 onprojectload();
264 void ncursesui::usage() {
265 kendinterface();
266 cout << "usage: motor [options] [project name]" << endl <<
267 "options are as follows:" << endl <<
268 "\t-a, --ascii\tuse ascii characters to draw lines" << endl <<
269 "\t-t, --debugtty\tuse the specified tty for debugging" << endl <<
270 "\t-h, --help\tdisplay this help screen" << endl;
273 bool ncursesui::regproject() {
274 bool r = false;
275 string fname, pname, lfname, postfix = ".motor";
276 char buf[512];
278 if(input(motorui::file, fname, _("add project to the registry: ")) == motorui::yes) {
279 if(!access(fname.c_str(), R_OK)) {
280 pname = justfname(fname);
282 if(pname.size() > postfix.size())
283 if(pname.substr(pname.size()-postfix.size()) == postfix)
284 pname.erase(pname.size()-postfix.size());
286 if(pname != justfname(fname)) {
287 bool updname = false;
289 while(!pname.empty() && !projectname(pname).empty()) {
290 updname = true;
291 sprintf(buf, _("Already registered! Rename %s (%s) to: "),
292 pname.c_str(), justfname(fname).c_str());
293 if(input(text, pname, buf) != motorui::yes)
294 pname = "";
297 if(!pname.empty()) {
298 if(updname) {
299 string nfname = justpathname(fname) + "/" + pname + postfix;
300 rename(fname.c_str(), nfname.c_str());
301 fname = nfname;
304 lfname = conf.getprojectdir() + pname;
305 symlink(fname.c_str(), lfname.c_str());
307 motorproject np(pname);
308 r = !np.empty();
309 if(!r) {
310 logf(_("~%s~ is not a motor project"), justfname(fname).c_str());
311 unlink(lfname.c_str());
314 } else {
315 logf(_("~%s~ is an invalid name for a motor project file"));
318 } else {
319 logf(_("Cannot access ~%s~"), justfname(fname).c_str());
323 return r;
326 const projectname ncursesui::selectproject(mgrmode amode, vector<string> templs) {
327 vector<projectname>::iterator i;
328 vector<projectname> pnames;
329 vector<string>::iterator is;
330 vector< pair<string, INT> >::iterator itnode;
331 vector< pair<string, INT> > tnodes;
333 dialogbox db;
334 INT j, baritem, menuitem, cid, lpid;
335 string templatelast, head;
336 projectname pname;
337 motorproject mp;
338 bool iterfirst = true;
340 if(amode == selectorcreate) {
341 db.setbar(new horizontalbar(getcolor(cp_menu), getcolor(cp_menusel),
342 _("Create/Import.."), _("Add"), _("Remove"), _("Open"), NULL_CONST_STR));
344 db.addkey(KEY_IC, 1);
345 db.addkey(KEY_DC, 2);
347 db.getbar()->item = 3;
349 db.setwindow(new textwindow(0, 0, (INT) (DIALOG_WIDTH*0.8),
350 DIALOG_HEIGHT, getcolor(cp_menufr), TW_CENTERED,
351 getcolor(cp_menuhl), _(" Projects registry ")));
353 } else {
354 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
355 getcolor(cp_menufr), TW_CENTERED, getcolor(cp_menuhl),
356 _(" Add a project ")));
359 db.settree(new treeview(getcolor(cp_menu), getcolor(cp_menusel),
360 getcolor(cp_menu), getcolor(cp_menu)));
362 treeview &tree = *db.gettree();
364 while(pname.empty()) {
365 if(tree.empty()) {
366 tree.clear();
367 tnodes.clear();
368 pnames = manager.getprojectlist();
370 for(i = pnames.begin(); i != pnames.end(); i++) {
371 for(itnode = tnodes.begin(); itnode != tnodes.end(); itnode++)
372 if(itnode->first == i->gettemplatename()) break;
374 if(!templs.empty())
375 if(find(templs.begin(), templs.end(), i->gettemplatename()) == templs.end())
376 continue;
378 if(itnode == tnodes.end()) {
379 j = tree.addnode(0, getcolor(cp_menuhl), NULL, " " + i->gettemplatename() + " ");
380 tnodes.push_back(pair<string, INT>(i->gettemplatename(), j));
381 itnode = tnodes.end()-1;
384 cid = tree.addleaf(itnode->second, 0,
385 i-pnames.begin()+1, " " + i->getname() + " ");
387 if(iterfirst)
388 if((project.empty() && (i->getname() == uiconf.getlastproject()))
389 || (i->getname() == project.getname())) {
390 lpid = cid;
394 if(iterfirst) tree.setcur(lpid);
397 /* if(tree.empty() && (amode == selectorcreate)) {
398 if(iterfirst) baritem = 0; else break;
399 } else {*/
400 if(!db.open(menuitem, baritem, (void **) &j)) break;
401 // }
403 iterfirst = false;
405 if((amode == selectonly) && j) {
406 pname = pnames[j-1];
407 } else
408 switch(baritem) {
409 case 0:
410 if(createproject()) {
411 pname = static_cast<projectname> (project);
413 break;
414 case 1:
415 if(regproject())
416 tree.clear();
417 break;
418 case 2:
419 if(j) {
420 mp = motorproject(pnames[j-1], LP_NOCHECK);
422 if(!mp.empty()) {
423 mp.remove();
424 tree.clear();
425 iterfirst = pnames.size() == 1;
428 break;
429 case 3:
430 if(j) {
431 pname = pnames[j-1];
433 break;
437 db.close();
438 return pname;
441 string ncursesui::selecttemplate(const string &def, const string &title) const {
442 dialogbox db;
443 string ret, lw, buf;
444 INT n, b, nnode, citem, id, cpid = -1;
445 vector<string> tlist;
446 vector<string>::iterator it;
447 vector< pair<string, INT> > nodes;
448 vector< pair<string, INT> >::iterator in;
450 tlist = manager.gettemplatelist();
452 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
453 getcolor(cp_menufr), TW_CENTERED, getcolor(cp_menuhl), title.c_str()));
454 db.settree(new treeview(getcolor(cp_menu), getcolor(cp_menusel),
455 getcolor(cp_menu), getcolor(cp_menu)));
457 for(it = tlist.begin(); it != tlist.end(); it++) {
458 lw = getrword(buf = *it, "/");
460 for(in = nodes.begin(), nnode = 0; !nnode && (in != nodes.end()); in++)
461 if(in->first == buf) nnode = in->second;
463 if(!nnode) {
464 nnode = db.gettree()->addnode(0, getcolor(cp_menuhl), NULL, " " + buf + " ");
465 nodes.push_back(pair<string, INT>(buf, nnode));
468 id = db.gettree()->addleaf(nnode, 0, it-tlist.begin()+1, " " + lw + " ");
469 if(*it == def) cpid = id;
472 db.gettree()->setcur(cpid);
474 while(1) {
475 if(db.open(n, b, (void **) &citem)) {
476 if(citem) {
477 ret = tlist[citem-1];
478 break;
480 } else {
481 ret = def;
482 break;
486 db.close();
488 return ret;
491 void ncursesui::mainloop() {
492 while(!terminate) {
493 workareaupdate();
495 if(ed.getfcount()) {
496 ed.open();
497 } else {
498 execmenubar();
503 void ncursesui::redraw() {
504 workareaupdate();
507 void ncursesui::initmenubar() {
508 verticalmenu *m;
509 menubar = horizontalmenu(1, 0, getcolor(cp_menu), getcolor(cp_menusel), getcolor(cp_menufr));
511 menubar.otherkeys = &horizontalmenukeys;
513 menubar.additem(_(" File "));
514 menubar.additem(_(" Edit "));
515 menubar.additem(_(" Project "));
516 menubar.additem(_(" VCS "));
517 menubar.additem(_(" Debug "));
518 menubar.additem(_(" Window "));
520 m = menubar.pulldown(0);
521 m->additem(_(" Load.. ^O"));
522 m->additem(_(" Save F2"));
523 m->additem(_(" Save as.."));
524 m->additem(_(" Save all"));
525 m->additem(_(" Close ^D"));
526 m->additem(_(" Generate.."));
527 m->addline();
528 m->additem(_(" Motor settings"));
529 m->additem(_(" External keys"));
530 m->additem(_(" Regexper A-R"));
531 m->addline();
532 m->additem(_(" Quit ^X"));
534 m = menubar.pulldown(1);
535 m->additem(_(" Toggle mark F3"));
536 m->additem(_(" Cut A-X"));
537 m->additem(_(" Copy A-C"));
538 m->additem(_(" Paste A-V"));
539 m->addline();
540 m->additem(_(" Toggle ins/overw Ins"));
541 m->addline();
542 m->additem(_(" Find ^F"));
543 m->additem(_(" Find again ^G"));
544 m->additem(_(" Replace ^R"));
545 m->additem(_(" Go to line.. A-L"));
546 m->addline();
547 m->additem(_(" Shft block fwd A-Tab"));
548 m->additem(_(" Shft block back A-Bsp"));
549 m->addline();
550 m->additem(_(" Undo ^U"));
552 m = menubar.pulldown(2);
553 m->additem(_(" Projects registry"));
554 m->addline();
555 m->additem(_(" Files.. F11"));
556 m->additem(_(" Directories.. ^F11"));
557 m->additem(_(" Project settings S-F11"));
558 m->addline();
559 m->additem(_(" Build F9"));
560 m->additem(_(" Clean S-F9"));
561 m->additem(_(" Make a target.. A-T"));
562 m->additem(_(" Regen. build stuff"));
563 m->additem(_(" Make a dist package"));
564 m->addline();
565 m->additem(_(" Find a symbol.. A-?"));
566 m->additem(_(" External output.."));
568 m = menubar.pulldown(3);
569 m->additem(_(" Check in/out"));
570 m->additem(_(" Import"));
571 m->additem(_(" Tag a release"));
573 m->addline();
574 m->additem(_(" Browse revisions.."));
575 m->addline();
576 m->additem(_(" Fork a branch"));
577 m->additem(_(" Merge branches.."));
579 m = menubar.pulldown(4);
580 m->additem(_(" Run program F12"));
581 m->additem(_(" Load core dump.."));
582 m->additem(_(" Arguments.. S-F12"));
583 m->additem(_(" Reset program ^F12"));
584 m->additem(_(" Call stack.. A-S"));
585 m->addline();
586 m->additem(_(" Set/Clear breakpoint ^B"));
587 m->additem(_(" Breakpoints A-B"));
588 m->addline();
589 m->additem(_(" Add watch ^W"));
590 m->additem(_(" Watches A-W"));
591 m->additem(_(" Evaluate/Modify A-E"));
592 m->addline();
593 m->additem(_(" Trace into F7"));
594 m->additem(_(" Step over F8"));
595 m->additem(_(" Go to cursor F4"));
597 m = menubar.pulldown(5);
598 m->additem(_(" Next ^N"));
599 m->additem(_(" Previous ^P"));
600 m->addline();
601 m->additem(_(" Window list F5"));
602 m->additem(_(" Last build messages F6"));
605 void ncursesui::execmenubar() {
606 INT h = 0, p = 0;
607 string buf;
609 if(menubar.open(&h, &p))
610 switch(h) {
611 case 1:
612 switch(p) {
613 case 1: hotkey(CTRL('o')); break;
614 case 2: ed.fsave(uieditor::savecurrent); break;
615 case 3: ed.fsave(uieditor::saveas); break;
616 case 4: ed.fsave(uieditor::saveall); break;
617 case 5: ed.closecurrentfile(); break;
618 case 6: generate(); break;
619 case 8: settings(); break;
620 case 9: extkeylist(); break;
621 case 10: regexper.exec(); break;
622 case 12: terminate = true; break;
624 break;
625 case 2:
626 switch(p) {
627 case 1: ed.switchmark(); break;
628 case 2: ed.clipboard(uieditor::cut); break;
629 case 3: ed.clipboard(uieditor::copy); break;
630 case 4: ed.clipboard(uieditor::paste); break;
631 case 6: ed.insertmode = !ed.insertmode; break;
632 case 8: hotkey(CTRL('f')); break;
633 case 9: hotkey(CTRL('g')); break;
634 case 10: hotkey(CTRL('r')); break;
635 case 11:
636 ed.gotoline();
637 break;
638 case 13:
639 ed.shiftident(-1);
640 ed.redraw();
641 break;
642 case 14:
643 ed.shiftident(+1);
644 ed.redraw();
645 break;
646 case 16:
647 ed.undo();
648 break;
650 break;
651 case 3:
652 switch(p) {
653 case 1:
654 pload();
655 break;
656 case 3:
657 projectedit(pfiles);
658 break;
659 case 4:
660 projectedit(pdirs);
661 break;
662 case 5:
663 projectedit(psettings);
664 break;
665 case 7:
666 hotkey(KEY_F(9));
667 break;
668 case 8:
669 project.clean();
670 break;
671 case 9:
672 maketarget();
673 break;
674 case 10:
675 project.regenerate();
676 break;
677 case 11:
678 dist();
679 break;
680 case 13:
681 uitb.exec();
682 break;
683 case 14:
684 showoutput();
685 break;
687 break;
688 case 4:
689 switch(p) {
690 case 1:
691 uv.check();
692 break;
693 case 2:
694 uv.import();
695 break;
696 case 3:
697 uv.tag();
698 break;
699 case 5:
700 uv.explore();
701 break;
702 case 7:
703 uv.forkbranch();
704 break;
705 case 8:
706 uv.merge();
707 break;
709 break;
710 case 5:
711 switch(p) {
712 case 1:
713 if(debugger.running()) {
714 debugger.cont();
715 } else {
716 debugger.run();
718 break;
719 case 2:
720 loadcore();
721 break;
722 case 3:
723 arguments();
724 break;
725 case 4:
726 debugger.kill();
727 break;
728 case 5:
729 hotkey(ALT('s'));
730 break;
731 case 7:
732 hotkey(CTRL('b'));
733 break;
734 case 8:
735 hotkey(ALT('b'));
736 break;
737 case 10:
738 hotkey(CTRL('w'));
739 break;
740 case 11:
741 hotkey(ALT('w'));
742 break;
743 case 12:
744 evaluate("");
745 break;
746 case 14:
747 debugger.step();
748 break;
749 case 15:
750 debugger.next();
751 break;
752 case 16:
753 hotkey(KEY_F(4));
754 break;
756 break;
757 case 6:
758 switch(p) {
759 case 1: ed.switchwindow(+1); break;
760 case 2: ed.switchwindow(-1); break;
761 case 4: ed.windowlist(); break;
762 case 5: hotkey(KEY_F(6)); break;
764 break;
768 bool ncursesui::horizontalmenukeys(horizontalmenu &hm, INT k) {
769 bool r = thisui.hotkey(k);
770 return thisui.terminate || r;
773 void ncursesui::workareaupdate() {
774 INT i;
776 if(ed.getfcount()) {
777 ed.redraw();
778 } else {
779 attrset(0);
780 for(i = 1; i < LINES-1; i++)
781 mvhline(i, 0, ' ', COLS);
784 statusupdate();
785 watcher.update();
788 void ncursesui::statusupdate() {
789 INT x, y;
790 string pname, fname;
792 if(!project.empty())
793 pname = (string) _("PROJECT: ") + project.getname();
795 if(ed.getfid()) {
796 fname = (string) _("FILE: ") + justfname(ed.getfid()) + " ";
797 ed.getpos(&x, &y);
800 attrset(getcolor(cp_bottom));
801 mvhline(0, 0, ' ', COLS);
802 mvprintw(0, 0, " MOTOR %s %s%s", VERSION, fname.c_str(), pname.c_str());
804 if(ed.getfcount())
805 mvprintw(0, COLS-18, "[%c%c%c] %5d:%5d",
806 ed.insertmode ? '-' : 'O',
807 ed.ismark() ? 'B' : '-',
808 ed.modified ? 'M' : '-',
809 x, y+1);
811 ed.updatecursor();
814 bool ncursesui::hotkey(INT k) {
815 INT modifiers = getctrlkeys(), line;
816 vector<motorconfiguration::extkey>::const_iterator ek;
817 string buf;
818 bool r = true;
820 switch(k) {
821 case KEY_F( 1):
822 help();
823 break;
825 case KEY_F( 4):
826 if(ed.getfid()) {
827 ed.getpos(0, &line);
828 debugger.tocursor(ed.getfid(), line+1);
830 break;
832 case KEY_F( 5):
833 ed.windowlist();
834 break;
836 case KEY_F( 6):
837 showmessages();
838 break;
840 case KEY_F( 7):
841 debugger.step();
842 break;
844 case KEY_F( 8):
845 debugger.next();
846 break;
848 case KEY_F( 9):
849 project.build();
850 if(executor.begin() != executor.end()) showmessages();
851 break;
853 case KEY_F(19):
854 project.clean();
855 break;
857 case KEY_F(11):
858 if(modifiers & SHIFT_PRESSED) projectedit(psettings); else
859 if(modifiers & CONTROL_PRESSED) projectedit(pdirs, true); else
860 projectedit(pfiles);
861 break;
863 case KEY_F(12):
864 if(modifiers & SHIFT_PRESSED) {
865 arguments();
866 } else if(modifiers & CONTROL_PRESSED) {
867 debugger.kill();
868 } else {
869 if(debugger.running()) {
870 debugger.cont();
871 } else {
872 debugger.run();
875 break;
877 case CTRL('e'):
878 nextmessage();
879 break;
881 case CTRL('n'):
882 ed.switchwindow(+1);
883 break;
885 case CTRL('p'):
886 ed.switchwindow(-1);
887 break;
889 case CTRL('o'):
890 ed.loadfile();
891 break;
893 case CTRL('b'):
894 if(ed.getfid()) {
895 ed.getpos(0, &line);
896 breakpoint bp(ed.getfid(), line+1);
898 if(debugger.isbreakpoint(bp)) {
899 debugger.removebreakpoint(bp);
900 } else {
901 debugger.addbreakpoint(bp);
904 ed.markbreakpoints();
906 break;
908 case CTRL('w'):
909 watcher.add();
910 break;
912 case CTRL('f'):
913 uigrep.grep();
914 break;
916 case CTRL('r'):
917 uigrep.replace();
918 break;
920 case CTRL('g'):
921 uigrep.again();
922 break;
924 case ALT('b'):
925 showbreakpoints();
926 break;
928 case ALT('w'):
929 watcher.exec();
930 break;
932 case ALT('e'):
933 evaluate("");
934 break;
936 case ALT('?'):
937 uitb.exec();
938 break;
940 case ALT('s'):
941 showstack();
942 break;
944 case ALT('r'):
945 regexper.exec();
946 break;
948 case ALT('t'):
949 maketarget();
950 break;
952 case CTRL('x'):
953 terminate = true;
954 break;
956 case KEY_F(10):
957 execmenubar();
958 break;
960 default:
961 if(r = ((ek = find(conf.extkeybegin(), conf.extkeyend(), k))
962 != conf.extkeyend())) {
963 ek->exec();
965 break;
968 return r;
971 bool ncursesui::isterminated() {
972 return terminate;
975 void ncursesui::textboxf(const string &title, const char *fmt, ...) {
976 va_list ap;
977 char buf[512];
978 va_start(ap, fmt);
979 vsprintf(buf, fmt, ap);
980 va_end(ap);
981 textbox(buf, title);
984 void ncursesui::textbox(const string &text, const string &title) {
985 dialogbox db;
987 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
988 getcolor(cp_menufr), TW_CENTERED));
990 db.setbrowser(new textbrowser(getcolor(cp_menu)));
992 db.setbar(new horizontalbar(getcolor(cp_menu),
993 getcolor(cp_menusel), _("Ok"), NULL_CONST_STR));
995 db.getwindow()->set_title(getcolor(cp_menuhl), title);
996 db.getbrowser()->setbuf(text);
998 db.open();
999 db.close();
1002 INT ncursesui::texteditboxkeys(texteditor &ed, INT k) {
1003 switch(k) {
1004 case CTRL('x'):
1005 thisui.texteditok = true;
1006 case 27:
1007 return -1;
1010 return 1;
1013 bool ncursesui::texteditbox(const string &title, string &text) {
1014 char *sp;
1015 texteditor ed;
1017 textwindow w(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT, getcolor(cp_menufr),
1018 TW_CENTERED, getcolor(cp_menuhl), "%s", title.c_str());
1020 w.open();
1022 w.separatey(w.y2-w.y1-2);
1023 w.write(w.x2-w.x1-20, w.y2-w.y1-1, getcolor(cp_menufr), "^X save ESC cancel");
1024 w.write(w.x2-w.x1-20, w.y2-w.y1-1, getcolor(cp_menuhl), "^X");
1025 w.write(w.x2-w.x1-11, w.y2-w.y1-1, getcolor(cp_menuhl), "ESC");
1027 ed.setcoords(w.x1+1, w.y1+1, w.x2-1, w.y2-2);
1028 ed.addscheme(cp_menufr, cp_menufr, 0, 0);
1030 ed.otherkeys = &texteditboxkeys;
1031 ed.wrap = false;
1033 texteditok = false;
1034 ed.load(text, "");
1035 ed.open();
1037 if(texteditok) {
1038 text = sp = ed.save("\r\n");
1039 delete sp;
1042 w.close();
1043 return texteditok;
1046 void ncursesui::help() {
1047 string helptext;
1049 helptext += _("F1 Display this help screen\n");
1050 helptext += _("F10 Activate menu\n");
1051 helptext += _("^X Quit motor\n\n");
1052 helptext += _("F2 Save current file\n");
1053 helptext += _("^O Load file\n");
1054 helptext += _("^D Close current editor window\n");
1055 helptext += _("F5 Editor files..\n");
1056 helptext += _("^N Next editor window\n");
1057 helptext += _("^P Previous editor window\n\n");
1058 helptext += _("Ins Toggle insert/overwrite mode\n");
1059 helptext += _("F3 Toggle block marking mode\n");
1060 helptext += _("Alt-X, ^Del Cut selected text\n");
1061 helptext += _("Alt-C, ^Ins Copy selected text\n");
1062 helptext += _("Alt-V, ^Ins Paste previously copied text\n");
1063 helptext += _("Alt-Tab Shift selected block forward\n");
1064 helptext += _("Alt-Backsp Shift selected block backward\n\n");
1065 helptext += _("^U Undo previous editor operation\n");
1066 helptext += _("^F Find text in current file\n");
1067 helptext += _("^G Find again\n");
1068 helptext += _("^R Search and replace\n");
1069 helptext += _("Alt-L Goto line..\n\n");
1070 helptext += _("Shift-F11 Project settings..\n");
1071 helptext += _("F11 Project files..\n");
1072 helptext += _("^F11 Project directories..\n\n");
1073 helptext += _("F9 Build a project\n");
1074 helptext += _("Shift-F9 Clean\n");
1075 helptext += _("Alt-T Make a specific target..\n");
1076 helptext += _("F12 Run program\n");
1077 helptext += _("Shift-F12 Specify program arguments\n");
1078 helptext += _("Alt-? Find a symbol definition in the source\n\n");
1079 helptext += _("F4 Go to cursor\n");
1080 helptext += _("F7 Debug mode: trace into\n");
1081 helptext += _("F8 Step over\n\n");
1082 helptext += _("^B Set breakpoint at current line\n");
1083 helptext += _("Alt-B Breakpoints..\n");
1084 helptext += _("^W Add watch\n");
1085 helptext += _("Alt-W Watches..\n");
1086 helptext += _("Alt-E Evaluate/modify..\n\n");
1087 helptext += _("Alt-R Invoke the regexper tool\n\n");
1088 helptext += _("Note: If your terminal doesn't allow using Alt-keys or\n");
1089 helptext += _(" Fx keys, you can use ESC 'letter or number' instead.\n");
1090 helptext += _(" '^' char means the key should be pressed with Ctrl.");
1092 textbox(helptext, _(" Help "));
1095 vector<motorui::editfile> ncursesui::geteditfiles() {
1096 INT saven, i, x, y;
1097 vector<motorui::editfile> v;
1099 saven = ed.getfnum();
1100 for(i = 0; i < ed.getfcount(); i++) {
1101 ed.setfnum(i);
1102 ed.getpos(&x, &y);
1103 v.push_back(motorui::editfile(ed.getfid(i), x, y+1));
1106 if(ed.getfcount() > 1) {
1107 v.push_back(v[saven]);
1108 v.erase(v.begin()+saven);
1111 ed.setfnum(saven);
1112 return v;
1115 vector<string> ncursesui::geteditfile(const string &fname) {
1116 INT saven, i;
1117 string buf;
1118 stringstream st;
1119 vector<string> r;
1121 for(i = 0; i < ed.getfcount(); i++) {
1122 if(samefile(fname, ed.getfid(i))) {
1123 saven = ed.getfnum();
1124 ed.setfnum(i);
1125 buf = ed.save("\n");
1126 ed.setfnum(saven);
1127 break;
1131 if(!buf.empty())
1132 breakintolines(buf, r);
1134 return r;
1137 string ncursesui::inputskel(const string &initval, const string &text, bool selmode) {
1138 INT line = LINES-2;
1139 INT mright = COLS-text.size();
1140 screenarea sarea(0, line, COLS, line);
1142 attrset(getcolor(cp_input));
1143 mvhline(line, 0, ' ', COLS);
1144 kwriteatf(0, line, getcolor(cp_input), "%s", text.c_str());
1146 if(selmode) {
1147 mright -= 8;
1148 kwriteatf(COLS-8, line, getcolor(cp_input), "[Ctrl-T]");
1149 inp.connectselector(selector);
1150 } else {
1151 inp.removeselector();
1154 inp.setvalue(initval);
1155 inp.setcoords(text.size(), line, mright);
1156 inp.exec();
1158 sarea.restore();
1159 return inp.getvalue();
1162 void ncursesui::initelements() {
1163 inp.setcolor(getcolor(cp_input), getcolor(cp_menufr));
1165 selwindow = textwindow(0, 0, (INT) (DIALOG_WIDTH*0.8),
1166 DIALOG_HEIGHT, getcolor(cp_menufr), TW_CENTERED);
1168 selector.setcolor(getcolor(cp_menu), getcolor(cp_menuhl),
1169 getcolor(cp_menusel), getcolor(cp_menu));
1172 bool ncursesui::editcloseall() {
1173 bool ret;
1175 if(ret = ed.fsave(uieditor::saveallask))
1176 while(ed.getfcount()) ed.close();
1178 return ret;
1181 bool ncursesui::changetemplate() {
1182 string nt = selecttemplate(project.gettemplatename());
1184 if(!nt.empty() && nt != project.gettemplatename())
1185 if(ask("NY", _("Warning: changing template will rearrange files in project. Proceed?")) == motorui::yes) {
1186 project.settemplate(nt);
1187 return true;
1190 return false;
1193 void ncursesui::populatesettingstree(treeview &tree) {
1194 string cflags, lflags;
1196 tree.clear();
1197 project.getflags(cflags, lflags);
1199 INT nmain = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Main "));
1200 INT nvcs = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Version control "));
1201 INT nmake = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Make "));
1203 tree.addleaff(nmain, 0, 10, _(" Version : %s "), project.getversion().c_str());
1204 tree.addleaff(nmain, 0, 11, _(" Template : %s "), project.gettemplatename().c_str());
1205 tree.addleaff(nmain, 0, 12, _(" Root directory : %s "), project.getrootdir().c_str());
1206 tree.addleaff(nmain, 0, 13, _(" Use GNU gettext for internationalization : %s "), BOOL_TO_STR(project.isgettextized()));
1208 if(vcs.enabled()) {
1209 tree.addleaff(nvcs, 0, 14, _(" %s: %s in %s "),
1210 project.getvcs().c_str(), project.getvcsmodulename().c_str(),
1211 project.getvcsroot().c_str());
1212 } else {
1213 tree.addleaf(nvcs, 0, 14, _(" Not under version control "));
1216 tree.addleaff(nmake, 0, 16, _(" Makefile mode : %s "), MAKEMODE_TO_STR(project.getmakemode()));
1217 tree.addleaff(nmake, 0, 17, _(" Compiler options : %s "), cflags.c_str());
1218 tree.addleaff(nmake, 0, 18, _(" Linker options : %s "), lflags.c_str());
1220 tree.addnode(0, getcolor(cp_menuhl), 30, _(" Files.. "));
1221 tree.addnode(0, getcolor(cp_menuhl), 31, _(" Directories.. "));
1224 bool ncursesui::projectsettings() {
1225 INT n, b, nfiles;
1226 void *p;
1227 dialogbox db;
1228 string cflags, lflags, buf;
1229 bool rc = false, trc;
1231 project.getflags(cflags, lflags);
1233 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
1234 getcolor(cp_menufr), TW_CENTERED, getcolor(cp_menuhl),
1235 _(" Project settings ")));
1236 db.settree(new treeview(getcolor(cp_menu), getcolor(cp_menusel),
1237 getcolor(cp_menu), getcolor(cp_menu)));
1238 db.setbar(new horizontalbar(getcolor(cp_menu), getcolor(cp_menusel),
1239 _("Change"), NULL_CONST_STR));
1241 nfiles = ed.getfcount();
1242 for(bool fin = false; nfiles == ed.getfcount() && !fin; ) {
1243 populatesettingstree(*db.gettree());
1244 if(fin = !db.open(n, b, &p)) break;
1246 switch((INT) p) {
1247 case 10:
1248 if(input(motorui::text, buf = project.getversion(),
1249 _("version: ")) == motorui::yes) {
1250 project.setversion(buf);
1252 break;
1254 case 11:
1255 if(changetemplate())
1256 rc = true;
1257 break;
1259 case 12:
1260 log(_("Cannot modify the root directory. Please move the files manually"));
1261 break;
1263 case 13:
1264 project.setgettextized(!project.isgettextized());
1265 break;
1267 case 14:
1268 if(vcs.enabled()) {
1269 if(ask("NY", _("Do you want to disable version control for the project?")) == motorui::yes) {
1270 project.setvcsmodule("");
1271 project.setvcsroot("");
1273 } else {
1274 uv.import();
1276 break;
1278 case 16:
1279 project.setmakemode(
1280 project.getmakemode() == motorproject::automake ?
1281 motorproject::manual :
1282 motorproject::automake);
1283 break;
1285 case 17:
1286 if(input(motorui::text, cflags, _("additional compiler command line options: "))
1287 != motorui::cancel) {
1288 project.setflags(cflags, lflags);
1290 break;
1292 case 18:
1293 if(input(motorui::text, lflags, _("additional linker command line options: "))
1294 != motorui::cancel) {
1295 project.setflags(cflags, lflags);
1297 break;
1299 case 30:
1300 if(projectcontents(pfiles, false))
1301 rc = true;
1302 break;
1303 case 31:
1304 if(projectcontents(pdirs, false))
1305 rc = true;
1306 break;
1310 db.close();
1311 return rc;
1314 motorui::askresult ncursesui::input(motorui::inputkind kind, string &result,
1315 const string &prompt) {
1316 string text;
1317 bool fselmode;
1318 INT fseloptions = 0;
1320 selwindow.set_title(getcolor(cp_menuhl), _(" <Ins> select; <Space> confirm; <Esc> cancel "));
1322 switch(kind) {
1323 case motorui::filechroot:
1324 fseloptions |= FSEL_CHROOT;
1325 fseloptions |= FSEL_MULTI;
1326 case motorui::file:
1327 fselmode = true;
1328 break;
1330 case motorui::directorychroot:
1331 fseloptions |= FSEL_CHROOT;
1332 case motorui::directory:
1333 fselmode = true;
1334 fseloptions |= FSEL_DIRSELECT;
1335 selector.setstartpoint(result);
1336 break;
1338 case motorui::text:
1339 fselmode = false;
1340 break;
1343 selector.setwindow(selwindow);
1344 selector.setoptions(fseloptions);
1346 text = inputskel(result, prompt, fselmode);
1348 if(inp.getlastkey() == KEY_ESC) {
1349 return motorui::cancel;
1352 result = text;
1353 return result.empty() ? motorui::no : motorui::yes;
1356 typedef pair<motorfile *, motorfolder *> shitpair;
1357 vector<shitpair> treeshit;
1359 void ncursesui::populatecontentstree(treeview &tree, motorproject &mp, projeditaction pea, bool setcurrent) {
1360 INT foldid, id, cfid = -1, i, sid;
1361 vector<motorfolder>::iterator ifold;
1362 vector<motorfile>::iterator ifile;
1363 static vector<string> cnodes;
1365 cnodes.clear();
1367 if(!tree.empty()) {
1368 for(i = 0; i < tree.menu.getcount(); i++) {
1369 id = tree.getid(i);
1371 if(tree.isnode(id))
1372 if(sid = (INT) tree.getref(id))
1373 if(!tree.isnodeopen(id))
1374 cnodes.push_back(treeshit[sid-1].second->gettagname());
1377 tree.clear();
1378 treeshit.clear();
1381 for(ifold = mp.foldbegin(); ifold != mp.foldend(); ifold++)
1382 if((pea == pfiles && ifold->getcontentkind() != motorfile::directory)
1383 || (pea == pdirs && ifold->getcontentkind() == motorfile::directory)) {
1385 treeshit.push_back(shitpair(0, &(*ifold)));
1386 foldid = tree.addnode(0, getcolor(cp_menuhl), treeshit.size(), " " + ifold->getname() + " ");
1388 if(find(cnodes.begin(), cnodes.end(), ifold->gettagname()) != cnodes.end()) {
1389 tree.closenode(foldid);
1390 } else {
1391 tree.opennode(foldid);
1394 for(ifile = ifold->begin(); ifile != ifold->end(); ifile++) {
1395 treeshit.push_back(shitpair(&(*ifile), &(*ifold)));
1396 id = tree.addleaf(foldid, 0, treeshit.size(), " " + ifile->getfname() + " ");
1398 if(setcurrent)
1399 if(ifold->getcontentkind() == motorfile::source)
1400 if(ifile->getfname() == mp.transformfname(motorproject::relative, ed.getfid()))
1401 cfid = id;
1405 tree.setcur(cfid);
1408 bool ncursesui::projectcontents(projeditaction pea, bool setcurrent) {
1409 INT n, b, citem, id;
1410 dialogbox db;
1411 string buf, head, fname;
1412 motorfolder *fold;
1413 motorfile *file;
1414 motorui::askresult ar;
1415 vector<string> templnames;
1416 verticalmenu m;
1417 projectname pname;
1419 bool fpass = true, tregen, rc = false;
1421 switch(pea) {
1422 case pfiles:
1423 head = _(" Project files ");
1424 db.setbar(new horizontalbar(getcolor(cp_menu),
1425 getcolor(cp_menusel), _("Add"), _("Remove"), _("Edit"), NULL_CONST_STR));
1426 db.getbar()->item = 2;
1427 break;
1428 case pdirs:
1429 head = _(" Project directories ");
1430 db.setbar(new horizontalbar(getcolor(cp_menu),
1431 getcolor(cp_menusel), _("Add"), _("Remove"), NULL_CONST_STR));
1432 break;
1435 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
1436 getcolor(cp_menufr), TW_CENTERED, getcolor(cp_menuhl), head.c_str()));
1438 db.settree(new treeview(getcolor(cp_menu), getcolor(cp_menusel),
1439 getcolor(cp_menu), getcolor(cp_menu)));
1441 treeview &tree = *db.gettree();
1443 tree.collapsable = true;
1444 db.addkey(KEY_IC, 0);
1445 db.addkey(KEY_DC, 1);
1447 for(bool fin = false; !fin; ) {
1448 if(tree.empty() || tregen) {
1449 populatecontentstree(tree, project, pea, setcurrent && ed.getfid() && fpass);
1450 tregen = false;
1452 if(tree.empty()) {
1453 log(_("No folders of this kind are defined in the template"));
1454 rc = false;
1455 break;
1459 if(fin = !db.open(n, b, (void **) &citem)) break;
1461 fpass = false;
1462 file = treeshit[citem-1].first;
1463 fold = treeshit[citem-1].second;
1465 switch(b) {
1466 case 0:
1467 ar = motorui::cancel;
1468 buf = "";
1470 switch(fold->getcontentkind()) {
1471 case motorfile::source:
1472 ar = input(motorui::filechroot, buf, _("add file: "));
1473 break;
1474 case motorfile::directory:
1475 ar = input(motorui::directory, buf, _("add directory: "));
1476 break;
1477 case motorfile::symbol:
1478 ar = input(motorui::text, buf, _("add symbol: "));
1479 break;
1480 case motorfile::project:
1481 pname = selectproject(selectonly, fold->gettempltotakefrom());
1482 if(!pname.empty()) {
1483 buf = pname.getname();
1484 ar = motorui::yes;
1486 break;
1489 if(ar == motorui::yes) {
1490 while(!buf.empty()) {
1491 fname = getword(buf, "\"");
1492 if(!fname.empty()) {
1493 fname = project.transformfname(projectpaths::relative, fname);
1495 if(find(fold->begin(), fold->end(), fname) == fold->end()) {
1496 if(fold->addfile(motorfile(fname), AF_VCS | AF_CHECKDIR | AF_TAKE)) {
1497 tregen = rc = true;
1498 } else {
1499 logf(_("Cannot add ~%s~ to the ~%s~ folder"),
1500 fname.c_str(), fold->getname().c_str());
1506 if(tregen) db.redraw();
1508 break;
1509 case 1:
1510 if(fold && file) {
1511 fold->removefile(*file);
1512 tregen = rc = true;
1513 db.redraw();
1515 break;
1516 case 2:
1517 if(fold && file)
1518 switch(fold->getcontentkind()) {
1519 case motorfile::source:
1520 ui.loadeditfile(editfile(file->getfname(), -1, 0),
1521 LF_CREATE_IF_NOTFOUND);
1522 fin = true;
1523 break;
1525 case motorfile::symbol:
1526 break;
1528 case motorfile::project:
1529 m = verticalmenu(getcolor(cp_menufr), getcolor(cp_menusel));
1530 m.setwindow(
1531 textwindow(db.getwindow()->x2-17,
1532 db.getwindow()->y2-3, db.getwindow()->x2+3,
1533 0, getcolor(cp_menufr)
1536 m.additem(_(" Files.."));
1537 m.additem(_(" Open the project"));
1539 if(project.getmakemode() == motorproject::automake)
1540 m.additem(_(" Build options.."));
1542 m.scale();
1543 n = m.open();
1544 m.close();
1546 switch(n) {
1547 case 1:
1548 buf = selectprojectfile(projectname(file->getfname()));
1549 if(fin = !buf.empty()) {
1550 ui.loadeditfile(editfile(buf, -1, 0), LF_CREATE_IF_NOTFOUND);
1552 break;
1553 case 2:
1554 pload(file->getfname());
1555 rc = false;
1556 fin = true;
1557 break;
1558 case 3:
1559 if(editbuildoptions(*file))
1560 rc = true;
1561 break;
1563 break;
1565 } else if(fold && !file) {
1566 id = tree.getid((void *) citem);
1568 if(tree.isnodeopen(id)) {
1569 tree.closenode(id);
1570 } else {
1571 tree.opennode(id);
1574 tree.redraw();
1577 break;
1581 db.close();
1582 return project.modified() || rc;
1585 string ncursesui::selectprojectfile(motorproject mp) {
1586 INT n, b, citem;
1587 string rc;
1588 dialogbox db;
1589 motorfolder *fold;
1590 motorfile *file;
1591 vector<shitpair> savetreeshit = treeshit;
1592 bool success;
1594 if(!mp.empty()) {
1595 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
1596 getcolor(cp_menufr), TW_CENTERED, getcolor(cp_menuhl),
1597 _(" Project %s "), mp.getname().c_str()));
1599 db.settree(new treeview(getcolor(cp_menu), getcolor(cp_menusel),
1600 getcolor(cp_menu), getcolor(cp_menu)));
1602 db.setbar(new horizontalbar(getcolor(cp_menu),
1603 getcolor(cp_menusel), _("Open"), NULL_CONST_STR));
1605 treeview &tree = *db.gettree();
1606 populatecontentstree(tree, mp, pfiles, false);
1608 while(1) {
1609 success = db.open(n, b, (void **) &citem);
1610 file = treeshit[citem-1].first;
1611 fold = treeshit[citem-1].second;
1612 if(!success || file) break;
1615 if(success && file) {
1616 if(fold->getcontentkind() == motorfile::source) {
1617 rc = file->getfname();
1621 db.close();
1624 treeshit = savetreeshit;
1625 return rc;
1628 bool ncursesui::autosave() {
1629 ed.fsave(uieditor::saveall);
1630 return true;
1633 void ncursesui::writeoutput(const string &text) {
1634 vector<string>::iterator il;
1635 INT pos, len = COLS-2, ln;
1636 string line;
1638 if(text.empty()) {
1639 outlines.push_back("");
1640 } else {
1641 for(pos = 0; pos < text.size(); pos += len) {
1642 line = text.substr(pos, len);
1643 outlines.push_back(line);
1647 while(outlines.size() > OUTLINES_LIMIT)
1648 outlines.erase(outlines.begin());
1650 if(!outputblocked) {
1651 if(!outopen) {
1652 outwindow.open();
1653 outopen = true;
1656 ln = outlines.size() >= LOOKER_HEIGHT ? 1 : LOOKER_HEIGHT-outlines.size();
1657 il = ln == 1 ? outlines.end()-LOOKER_HEIGHT+1 : outlines.begin();
1659 for(; il != outlines.end(); il++, ln++) {
1660 mvhline(ln, 0, ' ', COLS);
1662 if(il->substr(0, 1) == "\001") {
1663 kwriteat(0, ln, il->c_str()+1, boldcolor(0));
1664 } else {
1665 kwriteat(0, ln, il->c_str(), normalcolor(0));
1669 mvhline(ln, 0, ' ', COLS);
1670 kwriteat(0, ln, "", normalcolor(0));
1674 void ncursesui::doneoutput() {
1675 if(outopen) {
1676 outwindow.close();
1677 outopen = false;
1681 void ncursesui::showoutput() {
1682 textbrowser b(0, 1, COLS, LOOKER_HEIGHT+1, normalcolor(0));
1683 vector<string>::iterator i;
1684 string text;
1686 if(outlines.size() < LOOKER_HEIGHT)
1687 text.assign(LOOKER_HEIGHT-outlines.size()+1, '\n');
1689 for(i = outlines.begin(); i != outlines.end(); i++) {
1690 if(!text.empty()) text += "\n";
1691 text += *i;
1692 // text += (i->substr(0, 1) == "\001" ? i->substr(1) : *i);
1695 log(_("External output viewer, ~ESC~ to close"));
1696 b.setbuf(text.c_str());
1697 b.move(KEY_END);
1698 b.open();
1699 ed.redraw();
1700 log("");
1703 void ncursesui::pointmessage() {
1704 string lmsg;
1705 string::iterator i;
1706 INT k;
1708 if(!currentmsg->fname.empty())
1709 loadeditfile(editfile(currentmsg->fname, 0, currentmsg->line));
1711 k = 0;
1712 lmsg = currentmsg->description;
1713 i = lmsg.begin();
1715 while((i = find(i, lmsg.end(), '~')) != lmsg.end()) {
1716 lmsg.insert(i-lmsg.begin()+k, "~");
1717 i += 2;
1718 k++;
1721 log(lmsg);
1724 void ncursesui::showmessages() {
1725 INT h, pos;
1726 verticalmenu rm;
1727 vector<motorexecutor::message>::const_iterator i;
1728 bool curfound = false, start = false;
1730 if(executor.begin() != executor.end()) {
1731 rm = verticalmenu(getcolor(cp_menufr), getcolor(cp_menusel));
1733 for(i = executor.begin(); i != executor.end(); i++) {
1734 if(!i->fname.empty()) rm.additem(" " + justfname(i->fname) + ":" + i->description + " ");
1735 else rm.additem(" " + i->description);
1736 if(i == currentmsg) {
1737 rm.setpos(i-executor.begin());
1738 curfound = true;
1742 if(!curfound) currentmsg = executor.begin();
1743 if((h = rm.getcount()) > LINES-3) h = LINES-3;
1744 rm.setwindow(textwindow(0, LINES-3-h, COLS-1, LINES-2, getcolor(cp_menufr)));
1746 if(start = (pos = rm.open())) {
1747 currentmsg = executor.begin()+pos-1;
1750 rm.close();
1752 if(start) {
1753 pointmessage();
1755 } else {
1756 ui.log(_("No build messages"));
1760 void ncursesui::nextmessage() {
1761 if(executor.begin() != executor.end()) {
1762 if(++currentmsg != executor.end()) {
1763 pointmessage();
1764 } else {
1765 currentmsg--;
1766 log(_("At the end of the messages"));
1771 bool ncursesui::createproject() {
1772 dialogbox db;
1773 INT nopt, nproj, citem, n, b;
1774 bool ret = false, gnudoc, gettextized, gensource;
1775 enum {cmscratch, cmfiles, cmvcs} mode = cmscratch;
1776 string templname, pname, rootdir, vcsroot, vcsmodule, vcsrevision, buf, savename;
1777 motorproject::makemodekind makemode = motorproject::automake;
1778 projectname mp;
1779 motorproject oldproject;
1781 vector<string> vcses;
1782 vector<string>::iterator ivcs;
1784 gnudoc = gensource = true;
1785 gettextized = false;
1787 vcses = manager.getvcslist();
1788 ivcs = vcses.begin();
1790 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
1791 getcolor(cp_menufr), TW_CENTERED, getcolor(cp_menuhl),
1792 _(" Create a new project ")));
1794 db.setbar(new horizontalbar(getcolor(cp_menu), getcolor(cp_menusel),
1795 _("Change"), _("Create"), NULL_CONST_STR));
1797 db.settree(new treeview(getcolor(cp_menu), getcolor(cp_menusel),
1798 getcolor(cp_menu), getcolor(cp_menu)));
1800 treeview &tree = *db.gettree();
1802 for(bool fin = false; !fin; ) {
1803 tree.clear();
1805 nproj = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Project "));
1807 tree.addleaff(nproj, 0, 10, _(" Creation mode : %s "),
1808 mode == cmscratch ? _("from scratch") :
1809 mode == cmfiles ? _("from files") : _("from VCS"));
1811 tree.addleaff(nproj, 0, 11, _(" Template : %s "), templname.empty() ? _("none") : templname.c_str());
1812 tree.addleaff(nproj, 0, 12, _(" New project name : %s "), pname.c_str());
1813 tree.addleaff(nproj, 0, 13, _(" Root directory : %s "), rootdir.c_str());
1814 tree.addleaff(nproj, 0, 14, _(" Makefile mode : %s "), MAKEMODE_TO_STR(makemode));
1815 tree.addleaff(nproj, 0, 15, _(" GNU standard documentation : %s "), BOOL_TO_STR(gnudoc));
1816 tree.addleaff(nproj, 0, 19, _(" Use GNU gettext for internationalization : %s "), BOOL_TO_STR(gettextized));
1818 if(mode != cmfiles) {
1819 nopt = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Creation "));
1821 if(mode == cmscratch) {
1822 tree.addleaff(nopt, 0, 16, _(" Generate inital source: %s "), BOOL_TO_STR(gensource));
1823 } else if(mode == cmvcs) {
1824 tree.addleaff(nopt, 0, 20, _(" VCS name : %s "), ivcs->c_str());
1825 tree.addleaff(nopt, 0, 17, _(" Repository : %s "), vcsroot.c_str());
1826 tree.addleaff(nopt, 0, 18, _(" Module name : %s "), vcsmodule.c_str());
1827 tree.addleaff(nopt, 0, 21, _(" Revision : %s "), vcsrevision.c_str());
1831 if(!db.open(n, b, (void **) &citem)) {
1832 ret = false;
1833 fin = true;
1834 continue;
1837 switch(b) {
1838 case 0:
1839 switch(citem) {
1840 case 10:
1841 mode = mode == cmscratch ? cmfiles :
1842 mode == cmfiles ? cmvcs :
1843 cmscratch;
1845 if(mode == cmfiles)
1846 makemode = motorproject::manual;
1848 if((mode == cmvcs) && vcses.empty()) {
1849 log(_("No version control systems defined"));
1850 mode = cmscratch;
1853 break;
1855 case 11:
1856 templname = selecttemplate(templname);
1857 break;
1859 case 12:
1860 if(input(motorui::text, pname, _("project name: ")) == motorui::yes) {
1861 buf = rootdir.substr(0, conf.getdefaultprojectsdir().size());
1862 if(vcsmodule.empty()) vcsmodule = pname;
1863 if(rootdir.empty() || (buf == conf.getdefaultprojectsdir())) {
1864 rootdir = trailcut(conf.getdefaultprojectsdir(), "/") + "/" + pname;
1867 break;
1869 case 13:
1870 input(motorui::directory, rootdir, _("root directory: "));
1871 if(pname.empty()) pname = justfname(rootdir);
1872 break;
1874 case 14:
1875 makemode =
1876 makemode == motorproject::manual ?
1877 motorproject::automake :
1878 motorproject::manual;
1879 break;
1881 case 15: gnudoc = !gnudoc; break;
1882 case 16: gensource = !gensource; break;
1884 case 17:
1885 input(motorui::text, vcsroot, _("VCS repository to check out from: "));
1886 break;
1888 case 18:
1889 input(motorui::text, vcsmodule, _("VCS module name: "));
1890 break;
1892 case 19: gettextized = !gettextized; break;
1894 case 20:
1895 if(++ivcs == vcses.end())
1896 ivcs = vcses.begin();
1897 break;
1899 case 21:
1900 input(motorui::text, vcsrevision, _("VCS revision: "));
1901 break;
1903 break;
1905 case 1:
1906 ret = true;
1907 break;
1910 if(ret) {
1911 if(rootdir.empty()) {
1912 log(_("Project root directory must be set"));
1913 ret = false;
1916 if(ret)
1917 if(pname.empty()) {
1918 log(_("Project name must be set"));
1919 ret = false;
1922 if(ret)
1923 if(templname.empty()) {
1924 log(_("Template must be set"));
1925 ret = false;
1928 if(ret)
1929 if(!(mp = projectname(pname)).empty()) {
1930 logf(_("Project named %s already exists"), pname.c_str());
1931 ret = false;
1934 if(ret)
1935 if(pname.substr(0, 1).find_first_of("0123456789") != -1) {
1936 log(_("Project name cannot start with a number"));
1937 ret = false;
1940 if(ret)
1941 if(mode == cmvcs)
1942 if(vcsroot.empty() || vcsmodule.empty()) {
1943 log(_("VCS name, repository and module name must be specified"));
1944 ret = false;
1947 if(ret)
1948 if(mode != cmfiles)
1949 if(access(rootdir.c_str(), F_OK))
1950 if(ret = (ask("YNC", _("root directory you specified does not exist. create?")) == motorui::yes)) {
1951 mksubdirs(rootdir);
1954 if(ret)
1955 if(access(rootdir.c_str(), R_OK | W_OK | X_OK)) {
1956 log(_("Access denied for the directory specified"));
1957 ret = false;
1960 fin = ret;
1964 savename = project.getname();
1966 if(ret)
1967 if(project.close()) {
1968 project = motorproject();
1970 project.setname(pname);
1971 project.setversion("0.1");
1972 project.settemplate(templname);
1973 project.setrootdir(rootdir);
1974 project.setgettextized(gettextized);
1975 project.setmakemode(makemode);
1977 n = 0;
1978 if(gnudoc) n |= CR_GNU_DOC;
1980 switch(mode) {
1981 case cmscratch:
1982 if(gensource) n |= CR_GENERATE_SOURCE;
1983 break;
1984 case cmvcs:
1985 project.setvcs(*ivcs);
1986 project.setvcsroot(vcsroot);
1987 project.setvcsmodule(vcsmodule, vcsrevision);
1988 break;
1991 if(!(ret = project.create(n))) {
1992 if(!savename.empty()) {
1993 project = motorproject(projectname(savename));
1994 onprojectload();
1996 } else {
1997 vector<motordist>::const_iterator di;
1998 vector<motordist::distparam>::const_iterator pi;
2000 for(di = project.distbegin(); di != project.distend(); ++di)
2001 for(pi = di->parambegin(); pi != di->paramend(); ++pi)
2002 distparams[pi->name] = pi->defval;
2006 db.close();
2007 return ret;
2010 void ncursesui::dist() {
2011 INT maxl, i, b, fid;
2012 bool r, fin, first;
2013 textwindow *wdist;
2014 dialogbox db;
2015 vector<motordist>::const_iterator di;
2016 vector<motordist::distparam>::const_iterator pi;
2018 verticalmenu mdist(getcolor(cp_menu), getcolor(cp_menusel));
2020 if(project.distbegin() == project.distend()) {
2021 logf(_("No distribution methods defined in template %s"),
2022 project.gettemplatename().c_str());
2023 return;
2026 if(distdir.empty())
2027 distdir = project.getrootdir();
2029 for(maxl = 0, di = project.distbegin(); di != project.distend(); di++) {
2030 if(maxl < di->getname().size()) maxl = di->getname().size();
2031 mdist.additem(" " + di->getname());
2034 db.setwindow(wdist = new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT, getcolor(cp_menufr),
2035 TW_CENTERED, getcolor(cp_menuhl), _(" Distribution package generation ")));
2037 mdist.setwindow(textwindow(wdist->x1+6, wdist->y1+1, wdist->x1+9+maxl,
2038 wdist->y1+2+mdist.getcount(), getcolor(cp_menufr)));
2040 db.settree(new treeview(getcolor(cp_menu), getcolor(cp_menusel),
2041 getcolor(cp_menu), getcolor(cp_menu)));
2043 db.setbar(new horizontalbar(getcolor(cp_menu),
2044 getcolor(cp_menusel), _("Change"), _("Go!"), NULL_CONST_STR));
2046 di = project.distbegin();
2047 treeview &tree = *db.gettree();
2049 for(fin = r = false, first = true; !fin && !r; ) {
2050 tree.clear();
2052 i = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Format "));
2053 fid = tree.addleaf(i, 0, NULL, " " + di->getname() + " ");
2055 i = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Out directory "));
2056 tree.addleaf(i, 0, NULL, " " + distdir + " ");
2058 for(pi = di->parambegin(); pi != di->paramend(); ++pi) {
2059 if(pi == di->parambegin())
2060 i = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Parameters "));
2062 tree.addleaff(i, 0, NULL, " %s : %s ", pi->title.c_str(), distparams[pi->name].c_str());
2065 if(first) {
2066 tree.setcur(fid);
2067 b = 0;
2068 i = 2;
2069 first = false;
2070 db.redraw();
2071 } else {
2072 if(!db.open(i, b)) break;
2075 if(!(r = (b == 1))) {
2076 if(i == 2) {
2077 if(mdist.getcount() == 1) {
2078 di = project.distbegin();
2079 } else {
2080 if(i = mdist.open()) {
2081 di = project.distbegin()+i-1;
2083 mdist.close();
2085 } else if(i == 4) {
2086 input(motorui::directory, distdir, _("directory to put a dist to: "));
2087 } else if(i > 5) {
2088 pi = di->parambegin()+i-6;
2089 input(motorui::directory, distparams[pi->name], pi->title + ": ");
2094 db.close();
2095 if(r) {
2096 for(map<string, string>::const_iterator mi = distparams.begin(); mi != distparams.end(); ++mi)
2097 executor.setvar(mi->first, mi->second);
2099 di->exec(distdir);
2103 void ncursesui::executordone(const string &target, INT nerr, INT nwarn, INT ninfo) {
2104 if(nerr || nwarn || ninfo) {
2105 logf(_("Finished ~%s~: ~%lu~ errors, ~%lu~ warnings, ~%lu~ infos. ~F6~ to see the list"),
2106 target.c_str(), nerr, nwarn, ninfo);
2107 } else {
2108 logf(_("~%s~ finished sucessfully"), target.c_str());
2112 void ncursesui::projectedit(projeditaction pea, bool setcurrent) {
2113 bool modified = false;
2115 switch(pea) {
2116 case psettings: modified = projectsettings(); break;
2117 case pfiles: modified = projectcontents(pea, setcurrent); break;
2118 case pdirs: modified = projectcontents(pea); break;
2121 if(project.modified() || modified) {
2122 log(_("The project has been modified. Regenerating the build stuff.."));
2123 project.regenerate();
2124 project.save();
2128 void ncursesui::maketarget() {
2129 static INT pos = 0;
2130 static vector<string> targets;
2131 dialogbox db;
2132 string buf, tomake;
2133 vector<string>::iterator is;
2134 INT i, b;
2136 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
2137 getcolor(cp_menufr), TW_CENTERED, getcolor(cp_menuhl),
2138 _(" Make a target.. ")));
2139 db.setmenu(new verticalmenu(getcolor(cp_menu), getcolor(cp_menusel)));
2140 db.setbar(new horizontalbar(getcolor(cp_menu), getcolor(cp_menusel),
2141 _("Add"), _("Remove"), _("Make"), NULL_CONST_STR));
2143 db.addkey(KEY_IC, 0);
2144 db.addkey(KEY_DC, 1);
2145 db.getbar()->item = 2;
2147 for(bool fin = false; !fin; ) {
2148 db.getmenu()->clear();
2149 for(is = targets.begin(); is != targets.end(); is++)
2150 db.getmenu()->additem(" " + *is);
2151 db.getmenu()->setpos(pos);
2153 if(!(fin = !db.open(i, b))) {
2154 pos = db.getmenu()->getpos();
2156 switch(b) {
2157 case 0:
2158 if(input(motorui::text, buf = "", _("make a target: ")) == motorui::yes) {
2159 targets.push_back(buf);
2160 i = targets.size();
2162 case 2:
2163 if(fin = !targets.empty()) {
2164 tomake = targets[i-1];
2166 break;
2167 case 1:
2168 if(!targets.empty())
2169 targets.erase(targets.begin()+i);
2170 break;
2175 db.close();
2177 if(!tomake.empty()) {
2178 project.runtarget(tomake);
2182 void ncursesui::setdebugcurrentline(const editfile ef) {
2183 static INT prevfn, prevline;
2184 static string prevfname;
2185 vector<breakpoint> bps;
2186 vector<breakpoint>::iterator ibp;
2188 if((prevfname != ef.fname) || (prevline != ef.y)) {
2189 ed.unlight(prevfn, prevline);
2191 if(ed.getfid(prevfn)) {
2192 bps = debugger.getbreakpoints();
2194 if((ibp = find(bps.begin(), bps.end(), pair<string, INT>(ed.getfid(prevfn), prevline))) != bps.end())
2195 if(ibp->permanent())
2196 ed.highlight(prevfn, ibp->getline(), cp_debug_breakpoint);
2199 if(!ef.fname.empty()) {
2200 loadeditfile(ef);
2201 ed.highlight(ed.getfnum(), ef.y, cp_debug_current);
2204 prevfname = ef.fname;
2205 prevfn = ed.getfnum();
2206 prevline = ef.y;
2208 ed.redraw();
2212 void ncursesui::evaluate(const string &e) {
2213 dialogbox db;
2214 string val, buf;
2215 INT i, b, nexp;
2216 static string re;
2218 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, (INT) (DIALOG_HEIGHT*0.45),
2219 getcolor(cp_menufr), TW_CENTERED,
2220 getcolor(cp_menuhl), _(" Evaluate/Modify ")));
2222 db.settree(new treeview(getcolor(cp_menu), getcolor(cp_menusel),
2223 getcolor(cp_menu), getcolor(cp_menu)));
2225 db.setbar(new horizontalbar(getcolor(cp_menu),
2226 getcolor(cp_menusel), _("Change"), NULL_CONST_STR));
2228 if(!e.empty()) re = e;
2230 treeview &tree = *db.gettree();
2232 for(bool fin = false; !fin; ) {
2233 if(!re.empty()) {
2234 val = debugger.getvar(re);
2237 tree.clear();
2239 i = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Expression "));
2240 nexp = tree.addleaf(i, 0, NULL, " " + re + " ");
2242 i = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Value "));
2243 tree.addleaf(i, 0, NULL, " " + (val.empty() ? _("not available") : val) + " ");
2245 if(re.empty()) {
2246 i = 2;
2247 tree.setcur(nexp);
2248 } else {
2249 if(!db.open(i, b)) break;
2252 switch(i) {
2253 case 2:
2254 fin = input(motorui::text, re, _("expression: ")) != motorui::yes;
2255 break;
2256 case 4:
2257 watcher.modify(re, val);
2258 break;
2262 db.close();
2265 void ncursesui::settings() {
2266 dialogbox db;
2267 INT n, b, citem;
2268 bool fdispvcs, fdispmake, fdispcomp, fdebugstd, fchecktty, fmcedclip, fsmarttab;
2269 string fdefprojdir;
2271 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
2272 getcolor(cp_menufr), TW_CENTERED, getcolor(cp_menuhl),
2273 _(" Motor settings ")));
2275 db.setbar(new horizontalbar(getcolor(cp_menu),
2276 getcolor(cp_menusel), _("Change"), _("Done"), NULL_CONST_STR));
2278 db.settree(new treeview(getcolor(cp_menu), getcolor(cp_menusel),
2279 getcolor(cp_menu), getcolor(cp_menu)));
2281 treeview &tree = *db.gettree();
2283 fdebugstd = conf.getdebugstd();
2284 fdefprojdir = conf.getdefaultprojectsdir();
2285 fchecktty = conf.getchecktty();
2286 fmcedclip = uiconf.getmcedclip();
2287 fsmarttab = uiconf.getsmarttab();
2289 conf.getdisplay(fdispmake, fdispcomp, fdispvcs);
2291 for(bool fin = false; !fin; ) {
2292 tree.clear();
2294 n = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Show the run-time output "));
2295 tree.addleaff(n, 0, 1, _(" show compiler output : %s "), BOOL_TO_STR(fdispcomp));
2296 tree.addleaff(n, 0, 2, _(" show VCS output : %s "), BOOL_TO_STR(fdispvcs));
2297 tree.addleaff(n, 0, 3, _(" show make output : %s "), BOOL_TO_STR(fdispmake));
2299 n = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Debugger "));
2300 tree.addleaff(n, 0, 5, _(" debug standard headers : %s "), BOOL_TO_STR(fdebugstd));
2301 tree.addleaff(n, 0, 7, _(" disable free tty check : %s "), BOOL_TO_STR(!fchecktty));
2303 n = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Editor "));
2304 tree.addleaff(n, 0, 9, _(" enable \"smart tabs\" feature : %s "), BOOL_TO_STR(fsmarttab));
2305 tree.addleaff(n, 0, 8, _(" enable mcedit clipboard integration : %s "), BOOL_TO_STR(fmcedclip));
2307 n = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Directories and paths "));
2308 tree.addleaff(n, 0, 6, _(" default directory for projects : %s "), fdefprojdir.c_str());
2310 if(!db.open(n, b, (void **) &citem)) break;
2312 if(!b)
2313 switch(citem) {
2314 case 1: fdispcomp = !fdispcomp; break;
2315 case 2: fdispvcs = !fdispvcs; break;
2316 case 3: fdispmake = !fdispmake; break;
2317 case 5: fdebugstd = !fdebugstd; break;
2318 case 6:
2319 input(motorui::directory, fdefprojdir, _("default directory for projects: "));
2320 break;
2321 case 7: fchecktty = !fchecktty; break;
2322 case 8: fmcedclip = !fmcedclip; break;
2323 case 9: fsmarttab = !fsmarttab; break;
2324 } else {
2325 conf.setdefaultprojectsdir(fdefprojdir);
2326 conf.setdisplay(fdispmake, fdispcomp, fdispvcs);
2327 conf.setdebugstd(fdebugstd);
2328 conf.setchecktty(fchecktty);
2329 uiconf.setmcedclip(fmcedclip);
2331 uiconf.setsmarttab(fsmarttab);
2332 ed.smarttab = fsmarttab;
2334 conf.save();
2335 fin = true;
2339 db.close();
2342 void ncursesui::extkeylist() {
2343 INT count, i;
2344 vector<motorconfiguration::extkey>::const_iterator ik;
2345 verticalmenu m(getcolor(cp_menufr), getcolor(cp_menusel));
2347 if(count = conf.extkeyend()-conf.extkeybegin()) {
2348 for(ik = conf.extkeybegin(); ik != conf.extkeyend(); ik++) {
2349 m.additem(" " + ik->description());
2352 m.setwindow(textwindow(1, 1, (INT) (COLS*0.8), count > LINES-4 ? LINES-4 : count+2,
2353 getcolor(cp_menufr), 0, getcolor(cp_menuhl), _(" External programs ")));
2355 i = m.open();
2356 m.close();
2358 if(i) (conf.extkeybegin()+i-1)->exec();
2359 } else {
2360 log(_("No external keys defined"));
2364 void ncursesui::reloadeditfiles() {
2365 vector<motorui::editfile> openfiles;
2366 vector<motorui::editfile>::iterator iof;
2368 openfiles = geteditfiles();
2370 if(autosave()) {
2371 editcloseall();
2373 for(iof = openfiles.begin(); iof != openfiles.end(); iof++) {
2374 loadeditfile(*iof);
2379 void ncursesui::externalexec(INT options, const string &cmd) {
2380 INT i;
2381 string s;
2383 if(autosave()) {
2384 attrset(normalcolor(0));
2385 endwin();
2386 for(i = 0; i <= LINES; i++) cout << endl;
2387 cout << flush;
2389 system(cmd.c_str());
2391 if(options & EE_PAUSE) {
2392 cout << _("Press Enter to continue..") << flush;
2393 getstring(cin, s);
2396 refresh();
2397 reloadeditfiles();
2401 void ncursesui::showbreakpoints() {
2402 dialogbox db;
2403 INT n, b, i;
2404 vector<breakpoint> bps;
2405 vector<breakpoint>::iterator ib;
2406 editfile ef;
2408 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
2409 getcolor(cp_menufr), TW_CENTERED,
2410 getcolor(cp_menuhl), _(" Breakpoints ")));
2412 db.settree(new treeview(getcolor(cp_menu), getcolor(cp_menusel),
2413 getcolor(cp_menu), getcolor(cp_menu)));
2415 db.setbar(new horizontalbar(getcolor(cp_menu),
2416 getcolor(cp_menusel), _("Remove"), _("Goto"), NULL_CONST_STR));
2418 db.addkey(KEY_DC, 0);
2419 db.getbar()->item = 1;
2421 treeview &tree = *db.gettree();
2423 for(bool fin = false; !fin; ) {
2424 tree.clear();
2426 if(ed.getfid()) {
2427 INT x, y;
2428 ed.getpos(&x, &y);
2429 ef = editfile(ed.getfid(), x, y+1);
2432 for(bps = debugger.getbreakpoints(), ib = bps.begin(); ib != bps.end(); ib++) {
2433 i = tree.addleaff(0, 0, (ib-bps.begin()+1), " %s:%lu ",
2434 ib->getfname().c_str(), ib->getline());
2436 if((ib->getfname() == ef.fname) && (ib->getline() == ef.y))
2437 tree.setcur(i);
2440 ef = editfile();
2441 if(!db.open(n, b, (void **) &i)) break;
2443 if(i)
2444 switch(b) {
2445 case 0:
2446 ib = bps.begin()+i-1;
2447 debugger.removebreakpoint(*ib);
2448 break;
2449 case 1:
2450 fin = true;
2451 ib = bps.begin()+i-1;
2452 ef = editfile(ib->getfname(), 0, ib->getline());
2453 break;
2457 db.close();
2459 if(!ef.fname.empty()) {
2460 loadeditfile(ef);
2463 ed.markbreakpoints();
2466 void ncursesui::generate() {
2467 INT n, b;
2468 dialogbox db;
2469 vector<sourcetemplate> tg;
2470 vector<sourcetemplate>::const_iterator it;
2471 vector<sourcetemplate>::iterator itg;
2472 bool start = false;
2474 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
2475 getcolor(cp_menufr), TW_CENTERED, getcolor(cp_menuhl),
2476 _(" Files to generate ")));
2478 db.setmenu(new verticalmenu(getcolor(cp_menu), getcolor(cp_menusel)));
2480 db.setbar(new horizontalbar(getcolor(cp_menu), getcolor(cp_menusel),
2481 _("Mark"), _("Generate"), NULL_CONST_STR));
2483 db.addkey(' ', 0);
2484 verticalmenu &menu = *db.getmenu();
2486 for(bool fin = false; !fin; ) {
2487 menu.clear();
2489 for(it = project.templbegin(); it != project.templend(); it++) {
2490 menu.additemf(" [%c] %s ",
2491 find(tg.begin(), tg.end(), it->getfname()) != tg.end() ? 'x' : ' ',
2492 it->getfname().c_str());
2495 if(!db.open(n, b)) break;
2497 if(!b) {
2498 it = project.templbegin()+n-1;
2500 if((itg = find(tg.begin(), tg.end(), it->getfname())) != tg.end()) {
2501 tg.erase(itg);
2502 } else {
2503 tg.push_back(*it);
2505 } else {
2506 start = fin = true;
2510 db.close();
2512 if(start) {
2513 for(it = tg.begin(); it != tg.end(); it++) {
2514 it->generate();
2519 void ncursesui::arguments() {
2520 string buf;
2522 if(input(motorui::text, buf = project.getarguments(),
2523 _("arguments: ")) != motorui::cancel) {
2524 project.setarguments(buf);
2528 void ncursesui::loadcore() {
2529 dialogbox db;
2530 string corefname, r;
2531 INT n, b;
2533 if(input(motorui::file, corefname = project.getrootdir() + "/core",
2534 _("Core dump to explore: ")) == motorui::yes) {
2535 if(!(r = debugger.loadcore(corefname)).empty()) {
2536 log();
2538 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
2539 getcolor(cp_menufr), TW_CENTERED, getcolor(cp_menuhl),
2540 _(" Core dump load results ")));
2542 db.setbar(new horizontalbar(getcolor(cp_menu),
2543 getcolor(cp_menusel), _("Inspect stack"), _("Close"), NULL_CONST_STR));
2545 db.setbrowser(new textbrowser(getcolor(cp_menu)));
2546 db.getbrowser()->setbuf(r);
2548 for(bool fin = false; !fin; ) {
2549 fin = !db.open(n, b) || b;
2550 if(!fin) fin = showstack();
2553 db.close();
2558 bool ncursesui::showstack() {
2559 bool start;
2560 dialogbox db;
2561 vector<stackitem> stack;
2562 vector<stackitem>::iterator i;
2563 static INT savecount = 0, citem;
2564 INT n, b;
2565 string desc;
2567 start = false;
2569 if(!(stack = debugger.getstack()).empty()) {
2570 db.setwindow(new textwindow(0, 0, DIALOG_WIDTH, DIALOG_HEIGHT,
2571 getcolor(cp_menufr), TW_CENTERED,
2572 getcolor(cp_menuhl), _(" Call stack ")));
2574 db.setmenu(new verticalmenu(getcolor(cp_menu), getcolor(cp_menusel)));
2575 db.setbar(new horizontalbar(getcolor(cp_menu), getcolor(cp_menusel),
2576 _("Info"), _("Go to"), NULL_CONST_STR));
2578 db.getbar()->item = 1;
2580 for(i = stack.begin(); i != stack.end(); i++) {
2581 db.getmenu()->additemf(" %s() ", i->getname().c_str());
2584 if(savecount != stack.size()) {
2585 savecount = stack.size();
2586 citem = 0;
2587 } else {
2588 db.getmenu()->setpos(citem);
2591 for(bool fin = false; !fin; ) {
2592 if(!(fin = !db.open(n, b))) {
2593 i = stack.begin()+n-1;
2595 switch(b) {
2596 case 0:
2597 desc = _("Function:");
2598 desc += "\n " + i->getname() + "\n\n";
2599 desc += _("Location:");
2601 desc += "\n ";
2602 if(i->getlocation().fname.empty()) desc += "unknown";
2603 else desc += i->getlocation().fname + ":" + i2str(i->getlocation().y);
2604 desc += "\n\n";
2606 desc += _("Arguments:");
2607 desc += "\n " + i->getarguments();
2609 textbox(desc, _(" Stack item details "));
2610 break;
2611 case 1:
2612 start = fin = true;
2613 citem = n-1;
2614 break;
2619 db.close();
2621 if(start) {
2622 loadeditfile(i->getlocation());
2626 return start;
2629 void ncursesui::setdesktop(const vector< pair<string, string> > &asettings) {
2630 string afilter, param, buf;
2631 vector< pair<string, string> >::const_iterator i;
2632 vector< pair<char, string> >::const_iterator ik;
2634 watcher.close();
2635 distparams.clear();
2637 for(ik = project.tagnamebegin(); ik != project.tagnameend(); ++ik)
2638 afilter += ik->first;
2640 uitb.setfilter(afilter);
2642 for(i = asettings.begin(); i != asettings.end(); i++) {
2643 if(i->first == "ncurses_watchactive") {
2644 if(i->second == "1") watcher.activate();
2646 } else if(i->first == "distdir") {
2647 distdir = i->second;
2649 } else if(i->first.substr(0, 9) == "distparam") {
2650 buf = i->second;
2651 param = getword(buf);
2652 distparams[param] = buf;
2654 } else if(i->first == "tagbrowser_scope") {
2655 tagbrowser.setscope((motortagbrowser::viewscope)
2656 strtoul(i->second.c_str(), 0, 0));
2658 } else if(i->first == "tagbrowser_filter") {
2659 uitb.setfilter(i->second);
2665 vector< pair<string, string > > ncursesui::getdesktop() const {
2666 INT pn;
2667 vector< pair<string, string> > r;
2669 r.push_back(pair<string, string>("ncurses_watchactive",
2670 watcher.visible() ? "1" : "0"));
2672 r.push_back(pair<string, string>("distdir", distdir));
2673 r.push_back(pair<string, string>("tagbrowser_scope", i2str((INT) tagbrowser.getscope())));
2674 r.push_back(pair<string, string>("tagbrowser_filter", uitb.getfilter()));
2676 pn = 0;
2677 for(map<string, string>::const_iterator ip = distparams.begin(); ip != distparams.end(); ++ip, pn++)
2678 r.push_back(make_pair(string("distparam") + i2str(pn), ip->first + " " + ip->second));
2680 return r;
2683 void ncursesui::updatewatches() {
2684 watcher.update();
2687 bool ncursesui::editmodified() const {
2688 return ed.anymodified();
2691 void ncursesui::onprojectload() {
2692 project.editload();
2693 project.debugload();
2694 ed.markbreakpoints();
2695 selector.setstartpoint(project.getrootdir());
2696 logf(_("Project %s has been loaded"), project.getname().c_str());
2699 motorui::askresult ncursesui::notemplate(string &templname) const {
2700 char buf[512];
2701 sprintf(buf, _("%s not found, please select template"), templname.c_str());
2702 string nt = selecttemplate("", buf);
2704 if(!nt.empty()) templname = nt; else
2705 return cancel;
2707 return yes;
2710 bool ncursesui::editbuildoptions(motorfile &f) const {
2711 dialogbox db;
2712 INT i, n, b, citem;
2713 bool enabled, start;
2714 motorfile::build bd = f.getbuild();
2716 db.setwindow(new textwindow(0, 0, (INT) (DIALOG_WIDTH*0.9), (INT) (DIALOG_HEIGHT*0.6),
2717 getcolor(cp_menufr), TW_CENTERED,
2718 getcolor(cp_menuhl), _(" %s build options "),
2719 f.getfname().c_str()));
2721 db.settree(new treeview(getcolor(cp_menu), getcolor(cp_menusel),
2722 getcolor(cp_menu), getcolor(cp_menu)));
2724 db.setbar(new horizontalbar(getcolor(cp_menu),
2725 getcolor(cp_menusel), _("Change"), _("Done"), NULL_CONST_STR));
2727 treeview &tree = *db.gettree();
2729 start = false;
2730 enabled = !bd.param.empty();
2732 for(bool fin = false; !fin; ) {
2733 tree.clear();
2735 i = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" General "));
2736 tree.addleaff(i, 0, 1, _(" Enable optional build : %s "), BOOL_TO_STR(enabled));
2738 if(enabled) {
2739 i = tree.addnode(0, getcolor(cp_menuhl), NULL, _(" Build "));
2740 tree.addleaff(i, 0, 2, _(" Parameter name (--enable-xxx) : %s "), bd.param.c_str());
2741 tree.addleaff(i, 0, 3, _(" Parameter help text : %s "), bd.help.c_str());
2742 tree.addleaff(i, 0, 4, _(" Enabled by default : %s "), BOOL_TO_STR(bd.def));
2745 if(!db.open(n, b, (void **) &citem)) break;
2747 if(!b)
2748 switch(citem) {
2749 case 1: enabled = !enabled; break;
2750 case 2: ui.input(motorui::text, bd.param, _("configure parameter name (--enable-xxx): ")); break;
2751 case 3: ui.input(motorui::text, bd.help, _("help text: ")); break;
2752 case 4: bd.def = !bd.def; break;
2754 else {
2755 fin = start = true;
2759 db.close();
2761 if(start)
2762 f.setbuild(bd);
2764 return start;