1 
2 
3 /* This version of microEmacs is based on the public domain C
4  * version written by Dave G. Conroy.
5  * The D programming language version is written by Walter Bright.
6  * http://www.digitalmars.com/d/
7  * This program is in the public domain.
8  */
9 
10 /*
11  * This program is in public domain; written by Dave G. Conroy.
12  * This file contains the main driving routine, and some keyboard processing
13  * code, for the MicroEMACS screen editor.
14  *
15  * REVISION HISTORY:
16  *
17  * 1.0  Steve Wilhite, 30-Nov-85
18  *      - Removed the old LK201 and VT100 logic. Added code to support the
19  *        DEC Rainbow keyboard (which is a LK201 layout) using the the Level
20  *        1 Console In ROM INT. See "rainbow.h" for the function key definitions.
21  *
22  * 2.0  George Jones, 12-Dec-85
23  *      - Ported to Amiga.
24  *
25  * Later versions - Walter Bright, Bjorn Benson
26  *	- Ported to linux
27  *	- Ported to Win32 (compile with Digital Mars C compiler, www.digitalmars.com)
28  *	- Ported to DOS32
29  *
30  * The D programming language version
31  *	- translated to D by Walter Bright on 14-Feb-2008
32  *	- drops 16 bit versions, all versions other than Windows and Linux
33  */
34 
35 module main;
36 
37 import core.stdc.time;
38 import core.stdc.stdlib;
39 
40 import std..string;
41 import std.stdio;
42 import std.utf;
43 
44 import ed;
45 import file;
46 import buffer;
47 import window;
48 import basic;
49 import random;
50 import more;
51 import search;
52 import region;
53 import word;
54 import spawn;
55 import display;
56 import terminal;
57 import line;
58 import mouse;
59 import console;
60 
61 int     currow;                         /* Working cursor row           */
62 int     fillcol;                        /* Current fill column          */
63 int     thisflag;                       /* Flags, this command          */
64 int     lastflag;                       /* Flags, last command          */
65 int     curgoal;                        /* Goal column                  */
66 int     markcol;                        /* starting column for column cut */
67 int     hasmouse;                       /* TRUE if we have a mouse      */
68 BUFFER  *curbp;                         /* Current buffer               */
69 WINDOW  *curwp;                         /* Current window               */
70 BUFFER  *bheadp;                        /* BUFFER listhead              */
71 BUFFER  *blistp;                        /* Buffer list BUFFER           */
72 dchar[256] kbdm = [CTLX|')'];           /* Macro                        */
73 dchar   *kbdmip;                        /* Input  for above             */
74 dchar   *kbdmop;                        /* Output for above             */
75 string  pat;                            /* search pattern               */
76 ubyte   insertmode = 1;                 /* insert/overwrite mode        */
77 string  progname;                       /* this program name            */
78 
79 /+
80 int     basic_nextline();       /* Move to next line            */
81 int     basic_setmark();        /* Set mark                     */
82 
83 int     random_setfillcol();    /* Set fill column.             */
84 int     random_showcpos();      /* Show the cursor position     */
85 int     random_twiddle();       /* Twiddle characters           */
86 int     random_tab();           /* Insert tab                   */
87 int     random_hardtab();       // Set hardware tabs
88 int     random_newline();       /* Insert CR-LF                 */
89 int     random_indent();        /* Insert CR-LF, then indent    */
90 int     random_incindent();     /* increase indentation level   */
91 int     random_decindent();     /* decrease indentation level   */
92 int     random_opttab();        /* optimize tabbing in line     */
93 int     random_openline();      /* Open up a blank line         */
94 int     random_deblank();       /* Delete blank lines           */
95 int     random_quote();         /* Insert literal               */
96 int     random_forwdel();       /* Forward delete               */
97 int     random_backdel();       /* Backward delete              */
98 int     random_kill();          /* Kill forward                 */
99 int     random_yank();          /* Yank back from killbuffer.   */
100 int     random_undelchar();     /* Undelete a character         */
101 
102 int     region_togglemode();    /* Toggle column region mode    */
103 int     region_kill();          /* Kill region.                 */
104 int     region_copy();          /* Copy region to kill buffer.  */
105 
106 int     window_next();          /* Move to the next window      */
107 int     window_prev();          /* Move to the previous window  */
108 int     window_only();          /* Make current window only one */
109 int     window_split();         /* Split current window         */
110 int     window_mvdn();          /* Move window down             */
111 int     window_mvup();          /* Move window up               */
112 int     window_enlarge();       /* Enlarge display window       */
113 int     window_shrink();        /* Shrink window                */
114 int     window_reposition();    /* Reposition window            */
115 int     window_refresh();       /* Refresh the screen           */
116 
117 int     toggleinsert();         /* Toggle insert/overwrite mode */
118 int     line_overwrite();       /* Write char in overwrite mode */
119 int     ctrlg();                /* Abort out of things          */
120 int     quit();                 /* Quit                         */
121 int     main_saveconfig();      /* Save configuration           */
122 int     ctlxlp();               /* Begin macro                  */
123 int     ctlxrp();               /* End macro                    */
124 int     macrotoggle();          /* Start/End macro		*/
125 int     ctlxe();                /* Execute macro                */
126 int     filenext();             /* Edit next file               */
127 int     fileread();             /* Get a file, read only        */
128 int     filevisit();            /* Get a file, read write       */
129 int     filewrite();            /* Write a file                 */
130 int     fileunmodify();         /* Turn off buffer changed bits */
131 int     filesave();             /* Save current file            */
132 int     filename();             /* Adjust file name             */
133 int     getcol();               /* Get current column           */
134 int     gotobol();              /* Move to start of line        */
135 int     forwchar();             /* Move forward by characters   */
136 int     gotoeol();              /* Move to end of line          */
137 int     backchar();             /* Move backward by characters  */
138 int     forwline();             /* Move forward by lines        */
139 int     backline();             /* Move backward by lines       */
140 int     forwpage();             /* Move forward by pages        */
141 int     backpage();             /* Move backward by pages       */
142 int     gotobob();              /* Move to start of buffer      */
143 int     gotoeob();              /* Move to end of buffer        */
144 int     gotoline();             /* Move to line number          */
145 int     removemark();           /* Remove mark                  */
146 int     swapmark();             /* Swap "." and mark            */
147 int     forwsearch();           /* Search forward               */
148 int     backsearch();           /* Search backwards             */
149 int     search_paren();         /* Toggle over parentheses      */
150 int     listbuffers();          /* Display list of buffers      */
151 int     usebuffer();            /* Switch a window to a buffer  */
152 int     buffer_next();          /* Switch to next buffer        */
153 int     killbuffer();           /* Make a buffer go away.       */
154 int	word_wrap_line();	/* Word wrap current line	*/
155 int     word_select();          /* Select word                  */
156 int     word_back();            /* Backup by words              */
157 int     word_forw();            /* Advance by words             */
158 int     misc_upper();           /* Upper case word/region       */
159 int     misc_lower();           /* Lower case word/region       */
160 int     capword();              /* Initial capitalize word.     */
161 int     delfword();             /* Delete forward word.         */
162 int     delbword();             /* Delete backward word.        */
163 int     spawncli();             /* Run CLI in a subjob.         */
164 int     spawn();                /* Run a command in a subjob.   */
165 int     spawn_filter();         /* Filter buffer through program */
166 int     spawn_pipe();           /* Run program and gather output */
167 int     quickexit();            /* low keystroke style exit.    */
168 int     delwind();              /* Delete a window              */
169 int     filemodify();           /* Write modified files         */
170 int     normexit();             /* Write modified files and exit*/
171 int     replacestring();        /* Search and replace           */
172 int     queryreplacestring();   /* Query search and replace     */
173 int     win32toggle43();	/* Toggle 43 line mode          */
174 int     ibmpctoggle43();        /* Toggle 43 line mode          */
175 int     display_norm_fg();
176 int     display_norm_bg();
177 int     display_mode_fg();
178 int     display_mode_bg();
179 int     display_mark_fg();
180 int     display_mark_bg();
181 int     display_eol_bg();
182 int     Dignore();              /* do nothing                   */
183 int     Dsearch();              /* Search                       */
184 int     Dsearchagain();         /* Search for the same string   */
185 int     Ddelline();             /* Delete a line                */
186 int     Dundelline();           /* Undelete a line              */
187 int     Ddelword();             /* Delete a word                */
188 int     Ddelbword();            /* Delete a word (backwards)    */
189 int     Dundelword();           /* Undelete a word              */
190 int     Dadvance();             /* Set into advance mode        */
191 int     Dbackup();              /* Set into backup mode         */
192 int     Dpause();               /* Pause the program (UNIX only)*/
193 int     Dinsertdate();          /* File and date stamp          */
194 int     Dcppcomment();		/* convert to // comment	*/
195 int     Dinsertfile();          /* Insert a file                */
196 +/
197 
198 /*
199  * Command table.
200  * This table  is *roughly* in ASCII order, left to right across the
201  * characters of the command. This expains the funny location of the
202  * control-X commands.
203  */
204 
205 enum CMD_ENDMACRO = 0x8005;
206 
207 struct KEYTAB {
208     int k_code;                   /* Key code                     */
209     int function(bool, int) k_fp; /* Routine to handle it         */
210 }
211 
212 immutable KEYTAB[]  keytab =
213 [
214         /* Definitions common to all versions   */
215        { CTRL('@'),              &ctrlg}, /*basic_setmark*/
216        { CTRL('A'),              &gotobol},
217        { CTRL('B'),              &backchar},
218        { CTRL('C'),              &quit},
219        { CTRL('D'),              &random_forwdel},
220        { CTRL('E'),              &gotoeol},
221        { CTRL('F'),              &forwchar},
222        { CTRL('G'),              &ctrlg},
223        { CTRL('H'),              &random_backdel},
224        { CTRL('I'),              &random_tab},
225        { CTRL('J'),              &Ddelline},
226        { CTRL('K'),              &random_kill},
227        { CTRL('L'),              &window_refresh},
228        { CTRL('M'),              &random_newline},
229        { CTRL('N'),              &forwline},
230        { CTRL('O'),              &random_openline},
231        { CTRL('P'),              &backline},
232        { CTRL('Q'),              &random_quote},   /* Often unreachable    */
233        { CTRL('R'),              &backsearch},
234        { CTRL('S'),              &forwsearch},     /* Often unreachable    */
235        { CTRL('T'),              &random_twiddle},
236        { CTRL('V'),              &forwpage},
237        { CTRL('W'),              &search_paren},
238        { CTRL('Y'),              &random_yank},
239        { 0x7F,                   &random_backdel},
240 /+
241         /* Unused definitions from original microEMACS */
242        { CTRL('C'),              &spawncli},       /* Run CLI in subjob.   */
243        { CTRL('J'),              &random_indent},
244        { CTRL('W'),              &region_kill},
245        { CTRL('Z'),              &quickexit},      /* quick save and exit  */
246 +/
247        { CTRL('Z'),              &spawncli},      /* Run CLI in subjob.   */
248        { F2KEY,                  &Dsearchagain},
249        { F3KEY,                  &search_paren},
250        { F4KEY,                  &Dsearch},
251        { F5KEY,                  &basic_nextline},
252        { F6KEY,                  &window_next},
253        { F7KEY,                  &basic_setmark},
254        { F8KEY,                  &region_copy},
255        { F9KEY,                  &region_kill},
256        { F10KEY,                 &random_yank},
257 	{F11KEY,		 &ctlxe},
258 	{F12KEY,		 &macrotoggle},
259         {AltF1KEY,               &display_norm_bg},
260         {AltF2KEY,               &display_norm_fg},
261         {AltF3KEY,               &display_mode_bg},
262         {AltF5KEY,               &display_mark_fg},
263         {AltF6KEY,               &display_mark_bg},
264         {AltF4KEY,               &display_mode_fg},
265         {AltF7KEY,               &display_eol_bg},
266         {AltF9KEY,               &random_decindent},
267         {AltF10KEY,              &random_incindent},
268         {ALTB,                   &buffer_next},
269         {ALTC,                   &main_saveconfig},
270 	{ALTX,			 &normexit},
271         {ALTZ,                   &spawn_pipe},
272         {RTKEY,                  &forwchar},
273         {LTKEY,                  &backchar},
274         {DNKEY,                  &forwline},
275         {UPKEY,                  &backline},
276         {InsKEY,                 &toggleinsert},
277         {DelKEY,                 &random_forwdel},
278         {PgUpKEY,                &backpage},
279         {PgDnKEY,                &forwpage},
280         {HOMEKEY,                &window_mvup},
281         {ENDKEY,                 &window_mvdn},
282         {CtrlRTKEY,              &word_forw},
283         {CtrlLFKEY,              &word_back},
284         {CtrlHome,               &gotobob},
285         {CtrlEnd,                &gotoeob},
286 
287         /* Commands with a special key value    */
288         {0x8001,         &spawn_pipe},
289         {0x8002,         &spawn_filter},
290         {0x8003,         &random_showcpos},
291         {0x8004,         &ctlxlp},
292         {CMD_ENDMACRO,   &ctlxrp},
293         {0x8006,         &random_decindent},
294         {0x8007,         &random_incindent},
295         {0x8008,         &window_only},
296         {0x8009,         &removemark},
297         {0x800A,         &spawn.spawn},         /* Run 1 command.       */
298         {0x800B,         &window_split},
299         {0x800C,         &usebuffer},
300         {0x800D,         &delwind},
301         {0x800E,         &ctlxe},
302         {0x800F,         &random_setfillcol},
303         {0x8010,         &buffer.killbuffer},
304         {0x8011,         &window_next},
305         {0x8012,         &window_prev},
306         {0x8013,         &random_quote},
307         {0x8014,         &buffer_next},
308         {0x8015,         &window_enlarge},
309         {0x8016,         &listbuffers},
310         {0x8017,         &filename},
311         {0x8018,         &filemodify},
312         {0x8019,         &window_mvdn},
313         {0x801A,         &random_deblank},
314         {0x801B,         &window_mvup},
315         {0x801C,         &fileread},
316         {0x801D,         &filesave},       /* Often unreachable    */
317         {0x801E,         &window_reposition},
318         {0x801F,         &filevisit},
319         {0x8020,         &filewrite},
320         {0x8021,         &swapmark},
321         {0x8022,         &window_shrink},
322 
323         {0x8023,         &delbword},
324         {0x8024,         &random_opttab},
325         {0x8025,         &basic_setmark},
326         {0x8026,         &gotoeob},
327         {0x8027,         &gotobob},
328         {0x8028,         &region_copy},
329         {0x8029,         &region_kill},
330         {0x802A,         &word_back},
331         {0x802B,         &capword},
332         {0x802C,         &delfword},
333         {0x802D,         &word_forw},
334         {0x802E,         &misc_lower},
335         {0x802F,         &queryreplacestring},
336         {0x8030,         &replacestring},
337         {0x8031,         &misc_upper},
338         {0x8032,         &backpage},
339         {0x8033,         &word_select},
340         {0x8034,         &Dadvance},
341         {0x8035,         &Dbackup},
342         {0x8036,         &random_deblank},
343 
344         {0x8037,         &Dinsertdate},
345         {0x8038,         &Dinsertfile},
346         {0x8039,         &gotoline},
347         {0x803A,         &fileunmodify},
348         {0x803B,         &filenext},
349         {0x803C,         &quit},
350         {0x803D,         &normexit},
351         {0x803E,         &Dundelline},
352         {0x803F,         &Dsearch},
353         {0x8040,         &Dundelword},
354         {0x8041,         &random_undelchar},
355         {0x8042,         &random_openline},
356         {0x8043,         &random_kill},
357         {0x8044,         &region_togglemode},
358 	{0x8045,	 &Dcppcomment},
359 	{0x8046,	 &random_hardtab},
360 	{0x8047,	 &word_wrap_line},
361 	{0x8048,         &help},
362 	{0x8049,         &openBrowser},
363 	{0x804A,         &scrollUnicode},
364 ];
365 
366 /* Translation table from 2 key sequence to single value        */
367 immutable ushort[2][] altf_tab =
368 [
369         ['B',            0x8016],         /* listbuffers          */
370         ['D',            0x8037],         /* Dinsertdate          */
371         ['F',            0x8017],         /* filename             */
372         ['I',            0x8038],         /* Dinsertfile          */
373         ['M',            0x8018],         /* filemodify           */
374         ['N',            0x803B],         /* filenext             */
375         ['Q',            0x803C],         /* quit                 */
376         ['R',            0x801C],         /* fileread             */
377         ['S',            0x801D],         /* filesave             */
378 	['T',		 0x8046],	  // random_hardtab
379         ['U',            0x803A],         /* fileunmodify         */
380         ['V',            0x801F],         /* filevisit            */
381         ['W',            0x8020],         /* filewrite            */
382         ['X',            0x803D],         /* normexit             */
383         [F2KEY,          0x803E],         /* Dundelline           */
384         [F4KEY,          0x803F],         /* Dsearch              */
385         [CtrlRTKEY,      0x8040],         /* Dundelword           */
386         [CtrlLFKEY,      0x8040],         /* Dundelword           */
387         [DelKEY,         0x8041],         /* random_undelchar     */
388         [InsKEY,         0x8042],         /* random_openline      */
389 ];
390 
391 immutable ushort[2][] esc_tab =
392 [
393         ['.',            0x8025],         /* basic_setmark        */
394         ['>',            0x8026],         /* gotoeob              */
395         [ENDKEY,         0x8026],         /* gotoeob              */
396         ['<',            0x8027],         /* gotobob              */
397         [HOMEKEY,        0x8027],         /* gotobob              */
398         ['8',            0x8028],         /* region_copy          */
399         ['9',            0x8029],         /* region_kill          */
400         ['B',            0x802A],         /* word_back            */
401         ['C',            0x802B],         /* capword              */
402         ['D',            0x802C],         /* delfword             */
403         ['E',            0x8049],         // openBrowser
404         ['F',            0x802D],         /* word_forw            */
405         ['H',            0x8023],         /* delbword             */
406         ['I',            0x8024],         /* random_opttab        */
407 	['J',		 0x803E],		// Dundelline
408         ['L',            0x802E],         /* misc_lower           */
409         ['M',            0x8048],         // help
410         ['N',            0x8019],         /* window_mvdn          */
411         ['P',            0x801B],         /* window_mvup          */
412         ['Q',            0x802F],         /* queryreplacestring   */
413         ['R',            0x8030],         /* replacestring        */
414         ['T',            0x8044],         /* region_togglemode    */
415         ['U',            0x8031],         /* misc_upper           */
416         ['V',            0x8032],         /* backpage             */
417         ['W',            0x8033],         /* word_select          */
418         ['X',            0x8021],         /* swapmark             */
419         ['Z',            0x8022],         /* window_shrink        */
420         [DNKEY,          0x8034],         // Dadvance
421         [UPKEY,          0x8035],         // Dbackup
422 ];
423 
424 immutable ushort[2][] ctlx_tab =
425 [
426         ['@',            0x8001],	// spawn_pipe
427         ['#',            0x8002],	// spawn_filter
428         ['=',            0x8003],	// random_showcpos
429         ['(',            0x8004],	// ctlxlp
430         [')',            0x8005],	// ctlxrp
431         ['[',            0x8006],	// random_decindent
432         [']',            0x8007],	// random_incindent
433         ['.',            0x8009],	// removemark
434         ['!',            0x800A],	// spawn
435         ['1',            0x8008],	// window_only
436         ['2',            0x800B],	// window_split
437 	['A',		 0x8047],	// word_wrap_line
438         ['B',            0x800C],	// usebuffer
439         ['D',            0x800D],	// delwind
440         ['E',            0x800E],	// ctlxe
441         ['F',            0x800F],	// random_setfillcol
442         ['K',            0x8010],	// killbuffer
443         ['L',            0x8039],       // gotoline
444         ['N',            0x8011],	// window_next
445         ['O',            0x801A],       // random_deblank
446         ['P',            0x8012],	// window_prev
447         ['Q',            0x8013],	// random_quote
448         ['T',            0x801E],       // window_reposition
449         ['U',            0x804A],	// scrollUnicode
450         ['W',            0x8014],	// buffer_next
451         ['Z',            0x8015],	// window_enlarge
452 	['/',		 0x8045],	// Dcppcomment
453 ];
454 
455 struct CMDTAB
456 {   ushort    ktprefix;           /* prefix key value                     */
457     immutable ushort[2][]  kt;    /* which translation table              */
458 };
459 
460 CMDTAB[3] cmdtab =
461 [
462     {   CTLX,   ctlx_tab },
463     {   META,   esc_tab  },
464     {   GOLD,   altf_tab },
465 ];
466 
467 
468 string[] gargs;
469 int gargi;
470 
471 private int c;
472 
473 int main(string[] args)
474 {
475     bool   f;
476     int    n;
477     string bname;
478 
479     hasmouse = msm_init();                  /* initialize mouse     */
480     progname = args[0];                     /* remember program name */
481     bname = "main";                         /* Work out the name of */
482     if (args.length > 1)                    /* the default buffer.  */
483 	    bname = makename(args[1]);
484     vtinit();                               /* Displays.            */
485     edinit(bname);                          /* Buffers, windows.    */
486     if (args.length > 1) {
487 	    update();                       /* You have to update   */
488 	    readin(args[1]);                /* in case "[New file]" */
489     }
490     else
491 	mlwrite("[No file]");
492     gargi = 2;
493     gargs = args;
494     lastflag = 0;                           /* Fake last flags.     */
495     while (1)
496     {
497         update();                               /* Fix up the screen    */
498         c = getkey();
499         if (mpresf != FALSE)            /* if there is stuff in message line */
500         {   mlerase();                  /* erase it                     */
501             update();
502         }
503         f = FALSE;
504         n = 1;
505         if (c == CTRL('U'))                     /* ^U, start argument   */
506         {   f = TRUE;
507             n = getarg();
508         }
509         if (kbdmip != null) {                   /* Save macro strokes.  */
510                 if (c!=CMD_ENDMACRO && kbdmip>&kbdm[$-6]) {
511                         ctrlg(FALSE, 0);
512                         continue;
513                 }
514                 if (f != FALSE) {
515                         *kbdmip++ = CTRL('U');
516                         *kbdmip++ = n;
517                 }
518                 *kbdmip++ = c;
519         }
520         execute(0, c, f, n);                       /* Do it.               */
521     }
522     return 0;
523 }
524 
525 /******************************
526  * Get and return numeric argument.
527  */
528 
529 int getarg()
530 {
531     int n;
532     int mflag;
533 
534     n = 4;                          /* with argument of 4 */
535     mflag = 0;                      /* that can be discarded. */
536     mlwrite("Arg: 4");
537     while ((c=getkey()) >='0' && c<='9' || c==CTRL('U') || c=='-'){
538         if (c == CTRL('U'))
539             n = n*4;
540         /*
541          * If dash, and start of argument string, set arg.
542          * to -1.  Otherwise, insert it.
543          */
544         else if (c == '-') {
545             if (mflag)
546                 break;
547             n = 0;
548             mflag = -1;
549         }
550         /*
551          * If first digit entered, replace previous argument
552          * with digit and set sign.  Otherwise, append to arg.
553          */
554         else {
555             if (!mflag) {
556                 n = 0;
557                 mflag = 1;
558             }
559             n = 10*n + c - '0';
560         }
561         mlwrite("Arg: %d", (mflag >=0) ? n : (n ? -n : -1));
562     }
563     /*
564      * Make arguments preceded by a minus sign negative and change
565      * the special argument "^U -" to an effective "^U -1".
566      */
567     if (mflag == -1) {
568         if (n == 0)
569             n++;
570         n = -n;
571     }
572     return n;
573 }
574 
575 /*
576  * Initialize all of the buffers and windows. The buffer name is passed down
577  * as an argument, because the main routine may have been told to read in a
578  * file by default, and we want the buffer name to be right.
579  */
580 void edinit(string bname)
581 {
582         auto bp = buffer_find(bname, TRUE, 0);             /* First buffer         */
583         blistp = buffer_find("[List]", TRUE, BFTEMP); /* Buffer list buffer   */
584         auto wp = new WINDOW;                              // First window
585         if (bp==null || wp==null || blistp==null)
586         {       vttidy();
587                 exit(1);
588         }
589         bp.b_nwnd  = 1;                        /* Displayed.           */
590         curbp  = bp;                            /* Make this current    */
591         windows ~= wp;
592         curwp  = wp;
593         wp.w_bufp  = bp;
594         wp.w_linep = bp.b_linep;
595         wp.w_dotp  = bp.b_linep;
596         wp.w_ntrows = term.t_nrow-2;           /* -1 for mode line, -1 for minibuffer  */
597         wp.w_flag  = WFMODE|WFHARD;            /* Full.                */
598 }
599         
600 /*
601  * This is the general command execution routine. It handles the fake binding
602  * of all the keys to "self-insert". It also clears out the "thisflag" word,
603  * and arranges to move it to the "lastflag", so that the next command can
604  * look at it. Return the status of command.
605  */
606 int execute(int prefix, int c, bool f, int n)
607 {
608     int    status;
609 
610      /* Look in key table.   */
611     foreach (ktp; keytab)
612     {   if (ktp.k_code == c)
613         {   thisflag = 0;
614             status   = (*ktp.k_fp)(f, n);
615             lastflag = thisflag;
616             return (status);
617         }
618     }
619 
620     /*
621      * If a space was typed, fill column is defined, the argument is non-
622      * negative, and we are now past fill column, perform word wrap.
623      */
624     if (c == ' ' && fillcol > 0 && n>=0 &&
625 	getcol(curwp.w_dotp,curwp.w_doto) > fillcol)
626 	    word_wrap(false, 0);
627 
628     if ((c>=0x20 && c<=0x7E)                /* Self inserting.      */
629     ||  (c>=0xA0 && c<=0xFE)) {
630 	    if (n <= 0) {                   /* Fenceposts.          */
631 		    lastflag = 0;
632 		    return (n<0 ? FALSE : TRUE);
633 	    }
634 	    thisflag = 0;                   /* For the future.      */
635 	    status   = insertmode ? line_insert(n, cast(char)c) : line_overwrite(n, cast(char)c);
636 	    lastflag = thisflag;
637 	    return (status);
638     }
639 
640     /*
641      * Beep if an illegal key is typed
642      */
643     term.t_beep();
644     lastflag = 0;                           /* Fake last flags.     */
645     return (FALSE);
646 }
647 
648 /*
649  * Read in a key.
650  * Do the standard keyboard preprocessing. Convert the keys to the internal
651  * character set.
652  */
653 int getkey()
654 {
655     int    c;
656 
657     ttyield();
658     while (hasmouse && !ttkeysininput())
659     {   c = mouse_command();
660 	if (c)
661 	    return c;
662 	ttyield();
663         ttwaitkeys();
664     }
665     c = term.t_getchar();
666     switch (c)
667     {
668 /+
669             case MENU_BUTTON:
670                 c = memenu_button();
671                 break;
672 +/
673             case META:
674             case GOLD:
675             case CTLX:
676                 c = get2nd(c);
677                 break;
678 
679 	    default:
680 		break;
681     }
682 
683     return (c);
684 }
685 
686 /************************
687  * Get second key of two key command.
688  * Input:
689  *      the first key value
690  */
691 
692 static int get2nd(int flag)
693 {
694     int c;
695     int i,j;
696 
697 /+
698     auto starttime = clock();
699     while (!ttkeysininput())
700         if (clock() > starttime + CLK_TCK)
701         {   switch (flag)
702             {   case CTLX:
703                     return cast(ushort) memenu_ctlx(1,disp_cursorrow,disp_cursorcol);
704                 case GOLD:
705                     return cast(ushort) memenu_gold(1,disp_cursorrow,disp_cursorcol);
706                 case META:
707                     return cast(ushort) memenu_meta(1,disp_cursorrow,disp_cursorcol);
708             }
709         }
710 +/
711     c = term.t_getchar();
712 
713     /* Treat control characters and lowercase the same as upper case */
714     if (c>='a' && c<='z')                   /* Force to upper       */
715         c -= 0x20;
716     else if (c >= CTRL('A') && c <= CTRL('Z'))
717         c += 0x40;
718 
719     /* Translate to special keycode     */
720     for (i = 0; 1; i++)
721         if (cmdtab[i].ktprefix == flag)
722             break;
723     for (j = 0; 1; j++)
724     {
725         if (j == cmdtab[i].kt.length)
726         {   c = 0;
727             break;
728         }
729         if (cmdtab[i].kt[j][0] == c)
730         {   c = cmdtab[i].kt[j][1];
731             break;
732         }
733     }
734     return c;
735 }
736 
737 /*
738  * An even better exit command.  Writes all modified files and then
739  * exits.
740  */
741 int normexit(bool f, int n)
742 {
743     filemodify(f, n);                // write all modified files
744     update();    	             // make the screen look nice
745     quit(f, n);
746     return false;
747 }
748 
749 /*
750  * Quit command. If an argument, always quit. Otherwise confirm if a buffer
751  * has been changed and not written out. Normally bound to "C-X C-C".
752  */
753 int quit(bool f, int n)
754 {
755         if (f != FALSE                          /* Argument forces it.  */
756         || anycb() == FALSE                     /* All buffers clean.   */
757         || (mlyesno("Quit [y/n]? ")))           /* User says it's OK.   */
758         {   vttidy();
759             exit(0);
760         }
761         return FALSE;
762 }
763 
764 /*
765  * Begin a keyboard macro.
766  * Error if not at the top level in keyboard processing. Set up variables and
767  * return.
768  */
769 int ctlxlp(bool f, int n)
770 {
771         if (kbdmip!=null) {
772                 mlwrite("Not now: recording");
773                 return (FALSE);
774         }
775         if (kbdmop!=null) {
776                 mlwrite("Not now: executing");
777                 return (FALSE);
778         }
779         mlwrite("[Start macro]");
780         kbdmip = kbdm.ptr;
781 
782 	foreach (wp; windows)
783 	    wp.w_flag |= WFMODE;	/* so highlighting is updated */
784 
785         return (TRUE);
786 }
787 
788 /*
789  * End keyboard macro. Check for the same limit conditions as the above
790  * routine. Set up the variables and return to the caller.
791  */
792 int ctlxrp(bool f, int n)
793 {
794         if (kbdmip == null) {
795                 mlwrite("Not recording");
796                 return (FALSE);
797         }
798         mlwrite("[End macro]");
799         kbdmip = null;
800 
801 	foreach (wp; windows)
802 	    wp.w_flag |= WFMODE;	/* so highlighting is updated */
803 
804         return (TRUE);
805 }
806 
807 /*
808  * If in a macro
809  * 	end macro
810  * Else
811  *	start macro
812  */
813 
814 int macrotoggle(bool f, int n)
815 {
816         if (kbdmip)
817 	    return ctlxrp(f, n);
818 	else
819 	    return ctlxlp(f, n);
820 }
821 
822 /*
823  * Execute a macro.
824  * The command argument is the number of times to loop. Quit as soon as a
825  * command gets an error. Return TRUE if all ok, else FALSE.
826  */
827 int ctlxe(bool f, int n)
828 {
829         int    c;
830         bool   af;
831         int    an;
832         int    s;
833 
834         if (kbdmip!=null || kbdmop!=null) {
835                 /* Can't execute macro if defining a macro or if        */
836                 /* in the middle of executing one.                      */
837                 mlwrite("Not now");
838                 return (FALSE);
839         }
840         if (n <= 0)
841                 /* Execute macro 0 or fewer (!) times   */
842                 return (TRUE);
843         do {
844                 kbdmop = &kbdm[0];
845                 do {
846                         af = FALSE;
847                         an = 1;
848                         if ((c = *kbdmop++) == CTRL('U')) {
849                                 af = TRUE;
850                                 an = *kbdmop++;
851                                 c  = *kbdmop++;
852                         }
853                         s = TRUE;
854                 } while (c!=CMD_ENDMACRO && (s=execute(0, c, af, an))==TRUE);
855                 kbdmop = null;
856         } while (s==TRUE && --n);
857         return (s);
858 }
859 
860 /*
861  * Abort.
862  * Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
863  * Sometimes called as a routine, to do general aborting of stuff.
864  */
865 int ctrlg(bool f, int n)
866 {
867         term.t_beep();
868         if (kbdmip != null) {
869                 kbdm[0] = CMD_ENDMACRO;
870                 kbdmip  = null;
871         }
872         return ABORT;
873 }
874 
875 version (Windows)
876 {
877     CONFIG config =
878     {	// mode, norm, eol, mark, tab, url, search
879 	//0x74,0x02,0x07,0x24,
880 	//0x34,0x7F,0x78,0x3B,
881 	//0x34,0x0E,0x0E,0x3B,
882 	//0x34,0x70,0x70,0x3B,
883 	//0x34,0xF0,0xF0,0x3B,
884 	0x3E,0xF0,0xF0,0x3B,
885         ' '/*0xAF*/,
886 	0xF9,	// url
887 	0xE1,	// search
888 
889 	0xF9, //0xF3, // keyword
890 	0xFC, //0xF4, // string
891 	0xF8, //0xF2, // comment
892     };
893 }
894 else version (Posix)
895 {
896     CONFIG config =
897     {
898 	Color.bgCyan | Color.lightYellow,	// mode
899 	Color.black,	// norm
900 	Color.black,	// eol
901 	Color.reverse,	// mark
902 	' ',				// tab
903 	Color.underline | Color.blue,	// url
904 	Color.bgYellow | Color.black,	// search
905 
906 	Color.blue,	// keyword
907 	Color.red,	// string
908 	Color.magenta,	// comment
909     };
910 }
911 else
912 {
913     CONFIG config =
914     {
915 	Color.bright,	// mode
916 	0, 		// norm
917 	0,		// eol
918 	Color.bright,	// mark
919 	' ',		// tab
920 	0,		// url
921 	Color.yellow,	// search
922 	0,		// keyword
923 	0,		// string
924 	0,		// comment
925     };
926 }
927 
928 
929 /********************************
930  * Save configuration.
931  */
932 
933 int main_saveconfig(bool f, int n)
934 {
935     return FALSE;
936 }
937 
938 int toggleinsert(bool f, int n)
939 {
940     insertmode ^= 1;
941     term.t_setcursor(insertmode);
942     return true;
943 }
944