aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/boxes.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--boxes.c3423
1 files changed, 1712 insertions, 1711 deletions
diff --git a/boxes.c b/boxes.c
index ed63b44..038f48f 100644
--- a/boxes.c
+++ b/boxes.c
@@ -13,43 +13,43 @@
13USE_BOXES(NEWTOY(boxes, "w#h#m(mode):a(stickchars)1", TOYFLAG_USR|TOYFLAG_BIN)) 13USE_BOXES(NEWTOY(boxes, "w#h#m(mode):a(stickchars)1", TOYFLAG_USR|TOYFLAG_BIN))
14 14
15config BOXES 15config BOXES
16 bool "boxes" 16 bool "boxes"
17 default n 17 default n
18 help 18 help
19 usage: boxes [-m|--mode mode] [-a|--stickchars] [-w width] [-h height] 19 usage: boxes [-m|--mode mode] [-a|--stickchars] [-w width] [-h height]
20 20
21 Generic text editor and pager. 21 Generic text editor and pager.
22 22
23 Mode selects which editor or text viewr it emulates, the choices are - 23 Mode selects which editor or text viewr it emulates, the choices are -
24 emacs is a microemacs type editor. 24 emacs is a microemacs type editor.
25 joe is a joe / wordstar type editor. 25 joe is a joe / wordstar type editor.
26 less is a less type pager. 26 less is a less type pager.
27 mcedit (the default) is cooledit / mcedit type editor. 27 mcedit (the default) is cooledit / mcedit type editor.
28 more is a more type pager. 28 more is a more type pager.
29 nano is a nano / pico type editor. 29 nano is a nano / pico type editor.
30 vi is a vi type editor. 30 vi is a vi type editor.
31 31
32 Stick chars means to use ASCII for the boxes instead of "graphics" characters. 32 Stick chars means to use ASCII for the boxes instead of "graphics" characters.
33*/ 33*/
34 34
35#include "toys.h" 35#include "toys.h"
36 36
37GLOBALS( 37GLOBALS(
38 char *mode; 38 char *mode;
39 long h, w; 39 long h, w;
40 // TODO - actually, these should be globals in the library, and leave this buffer alone. 40 // TODO - actually, these should be globals in the library, and leave this buffer alone.
41 int stillRunning; 41 int stillRunning;
42 int overWriteMode; 42 int overWriteMode;
43) 43)
44 44
45#define TT this.boxes 45#define TT this.boxes
46 46
47#define FLAG_a 2 47#define FLAG_a 2
48#define FLAG_m 4 48#define FLAG_m 4
49#define FLAG_h 8 49#define FLAG_h 8
50#define FLAG_w 16 50#define FLAG_w 16
51 51
52#define MEM_SIZE 128 52#define MEM_SIZE 128
53 53
54/* This is trying to be a generic text editing, text viewing, and terminal 54/* This is trying to be a generic text editing, text viewing, and terminal
55 * handling system. The current code is a work in progress, and the design 55 * handling system. The current code is a work in progress, and the design
@@ -291,8 +291,8 @@ sized morsels?
291 291
292struct key 292struct key
293{ 293{
294 char *code; 294 char *code;
295 char *name; 295 char *name;
296}; 296};
297 297
298// This table includes some variations I have found on some terminals, and the MC "Esc digit" versions. 298// This table includes some variations I have found on some terminals, and the MC "Esc digit" versions.
@@ -309,126 +309,126 @@ struct key
309// Plus, human typing speeds wont need binary searching speeds on this small table. 309// Plus, human typing speeds wont need binary searching speeds on this small table.
310struct key keys[] = 310struct key keys[] =
311{ 311{
312 {"\x1B[3~", "Del"}, 312 {"\x1B[3~", "Del"},
313 {"\x1B[2~", "Ins"}, 313 {"\x1B[2~", "Ins"},
314 {"\x1B[D", "Left"}, 314 {"\x1B[D", "Left"},
315 {"\x1BOD", "Left"}, 315 {"\x1BOD", "Left"},
316 {"\x1B[C", "Right"}, 316 {"\x1B[C", "Right"},
317 {"\x1BOC", "Right"}, 317 {"\x1BOC", "Right"},
318 {"\x1B[A", "Up"}, 318 {"\x1B[A", "Up"},
319 {"\x1BOA", "Up"}, 319 {"\x1BOA", "Up"},
320 {"\x1B[B", "Down"}, 320 {"\x1B[B", "Down"},
321 {"\x1BOB", "Down"}, 321 {"\x1BOB", "Down"},
322 {"\x1B\x4f\x48", "Home"}, 322 {"\x1B\x4f\x48", "Home"},
323 {"\x1B[1~", "Home"}, 323 {"\x1B[1~", "Home"},
324 {"\x1B[7~", "Home"}, 324 {"\x1B[7~", "Home"},
325 {"\x1B[H", "Home"}, 325 {"\x1B[H", "Home"},
326 {"\x1BOH", "Home"}, 326 {"\x1BOH", "Home"},
327 {"\x1B\x4f\x46", "End"}, 327 {"\x1B\x4f\x46", "End"},
328 {"\x1B[4~", "End"}, 328 {"\x1B[4~", "End"},
329 {"\x1B[8~", "End"}, 329 {"\x1B[8~", "End"},
330 {"\x1B[F", "End"}, 330 {"\x1B[F", "End"},
331 {"\x1BOF", "End"}, 331 {"\x1BOF", "End"},
332 {"\x1BOw", "End"}, 332 {"\x1BOw", "End"},
333 {"\x1B[5~", "PgUp"}, 333 {"\x1B[5~", "PgUp"},
334 {"\x1B[6~", "PgDn"}, 334 {"\x1B[6~", "PgDn"},
335 {"\x1B\x4F\x50", "F1"}, 335 {"\x1B\x4F\x50", "F1"},
336 {"\x1B[11~", "F1"}, 336 {"\x1B[11~", "F1"},
337 {"\x1B\x31", "F1"}, 337 {"\x1B\x31", "F1"},
338 {"\x1BOP", "F1"}, 338 {"\x1BOP", "F1"},
339 {"\x1B\x4F\x51", "F2"}, 339 {"\x1B\x4F\x51", "F2"},
340 {"\x1B[12~", "F2"}, 340 {"\x1B[12~", "F2"},
341 {"\x1B\x32", "F2"}, 341 {"\x1B\x32", "F2"},
342 {"\x1BOO", "F2"}, 342 {"\x1BOO", "F2"},
343 {"\x1B\x4F\x52", "F3"}, 343 {"\x1B\x4F\x52", "F3"},
344 {"\x1B[13~", "F3"}, 344 {"\x1B[13~", "F3"},
345 {"\x1B\x33~", "F3"}, 345 {"\x1B\x33~", "F3"},
346 {"\x1BOR", "F3"}, 346 {"\x1BOR", "F3"},
347 {"\x1B\x4F\x53", "F4"}, 347 {"\x1B\x4F\x53", "F4"},
348 {"\x1B[14~", "F4"}, 348 {"\x1B[14~", "F4"},
349 {"\x1B\x34", "F4"}, 349 {"\x1B\x34", "F4"},
350 {"\x1BOS", "F4"}, 350 {"\x1BOS", "F4"},
351 {"\x1B[15~", "F5"}, 351 {"\x1B[15~", "F5"},
352 {"\x1B\x35", "F5"}, 352 {"\x1B\x35", "F5"},
353 {"\x1B[17~", "F6"}, 353 {"\x1B[17~", "F6"},
354 {"\x1B\x36", "F6"}, 354 {"\x1B\x36", "F6"},
355 {"\x1B[18~", "F7"}, 355 {"\x1B[18~", "F7"},
356 {"\x1B\x37", "F7"}, 356 {"\x1B\x37", "F7"},
357 {"\x1B[19~", "F8"}, 357 {"\x1B[19~", "F8"},
358 {"\x1B\x38", "F8"}, 358 {"\x1B\x38", "F8"},
359 {"\x1B[20~", "F9"}, 359 {"\x1B[20~", "F9"},
360 {"\x1B\x39", "F9"}, 360 {"\x1B\x39", "F9"},
361 {"\x1B[21~", "F10"}, 361 {"\x1B[21~", "F10"},
362 {"\x1B\x30", "F10"}, 362 {"\x1B\x30", "F10"},
363 {"\x1B[23~", "F11"}, 363 {"\x1B[23~", "F11"},
364 {"\x1B[24~", "F12"}, 364 {"\x1B[24~", "F12"},
365 {"\x1B\x4f\x31;2P", "Shift F1"}, 365 {"\x1B\x4f\x31;2P", "Shift F1"},
366 {"\x1B[1;2P", "Shift F1"}, 366 {"\x1B[1;2P", "Shift F1"},
367 {"\x1B\x4f\x31;2Q", "Shift F2"}, 367 {"\x1B\x4f\x31;2Q", "Shift F2"},
368 {"\x1B[1;2Q", "Shift F2"}, 368 {"\x1B[1;2Q", "Shift F2"},
369 {"\x1B\x4f\x31;2R", "Shift F3"}, 369 {"\x1B\x4f\x31;2R", "Shift F3"},
370 {"\x1B[1;2R", "Shift F3"}, 370 {"\x1B[1;2R", "Shift F3"},
371 {"\x1B\x4f\x31;2S", "Shift F4"}, 371 {"\x1B\x4f\x31;2S", "Shift F4"},
372 {"\x1B[1;2S", "Shift F4"}, 372 {"\x1B[1;2S", "Shift F4"},
373 {"\x1B[15;2~", "Shift F5"}, 373 {"\x1B[15;2~", "Shift F5"},
374 {"\x1B[17;2~", "Shift F6"}, 374 {"\x1B[17;2~", "Shift F6"},
375 {"\x1B[18;2~", "Shift F7"}, 375 {"\x1B[18;2~", "Shift F7"},
376 {"\x1B[19;2~", "Shift F8"}, 376 {"\x1B[19;2~", "Shift F8"},
377 {"\x1B[20;2~", "Shift F9"}, 377 {"\x1B[20;2~", "Shift F9"},
378 {"\x1B[21;2~", "Shift F10"}, 378 {"\x1B[21;2~", "Shift F10"},
379 {"\x1B[23;2~", "Shift F11"}, 379 {"\x1B[23;2~", "Shift F11"},
380 {"\x1B[24;2~", "Shift F12"}, 380 {"\x1B[24;2~", "Shift F12"},
381 381
382// {"\x00", "^@"}, // NUL Commented out coz it's the C string terminator, and may confuse things. 382// {"\x00", "^@"}, // NUL Commented out coz it's the C string terminator, and may confuse things.
383 {"\x01", "^A"}, // SOH 383 {"\x01", "^A"}, // SOH
384 {"\x02", "^B"}, // STX 384 {"\x02", "^B"}, // STX
385 {"\x03", "^C"}, // ETX SIGTERM 385 {"\x03", "^C"}, // ETX SIGTERM
386 {"\x04", "^D"}, // EOT 386 {"\x04", "^D"}, // EOT
387 {"\x05", "^E"}, // ENQ 387 {"\x05", "^E"}, // ENQ
388 {"\x06", "^F"}, // ACK 388 {"\x06", "^F"}, // ACK
389 {"\x07", "^G"}, // BEL 389 {"\x07", "^G"}, // BEL
390 {"\x08", "Del"}, // BS Delete key, usually. 390 {"\x08", "Del"}, // BS Delete key, usually.
391 {"\x09", "Tab"}, // HT Tab key. 391 {"\x09", "Tab"}, // HT Tab key.
392 {"\x0A", "Return"}, // LF Return key. Roxterm at least is translating both Ctrl-J and Ctrl-M into this. 392 {"\x0A", "Return"}, // LF Return key. Roxterm at least is translating both Ctrl-J and Ctrl-M into this.
393 {"\x0B", "^K"}, // VT 393 {"\x0B", "^K"}, // VT
394 {"\x0C", "^L"}, // FF 394 {"\x0C", "^L"}, // FF
395 {"\x0D", "^M"}, // CR Other Return key, usually. 395 {"\x0D", "^M"}, // CR Other Return key, usually.
396 {"\x0E", "^N"}, // SO 396 {"\x0E", "^N"}, // SO
397 {"\x0F", "^O"}, // SI 397 {"\x0F", "^O"}, // SI
398 {"\x10", "^P"}, // DLE 398 {"\x10", "^P"}, // DLE
399 {"\x11", "^Q"}, // DC1 399 {"\x11", "^Q"}, // DC1
400 {"\x12", "^R"}, // DC2 400 {"\x12", "^R"}, // DC2
401 {"\x13", "^S"}, // DC3 401 {"\x13", "^S"}, // DC3
402 {"\x14", "^T"}, // DC4 402 {"\x14", "^T"}, // DC4
403 {"\x15", "^U"}, // NAK 403 {"\x15", "^U"}, // NAK
404 {"\x16", "^V"}, // SYN 404 {"\x16", "^V"}, // SYN
405 {"\x17", "^W"}, // ETB 405 {"\x17", "^W"}, // ETB
406 {"\x18", "^X"}, // CAN 406 {"\x18", "^X"}, // CAN
407 {"\x19", "^Y"}, // EM 407 {"\x19", "^Y"}, // EM
408 {"\x1A", "^Z"}, // SUB 408 {"\x1A", "^Z"}, // SUB
409 {"\x1B", "^["}, // ESC Esc key. Commented out coz it's the ANSI start byte in the above multibyte keys. Handled in the code with a timeout. 409// {"\x1B", "^["}, // ESC Esc key. Commented out coz it's the ANSI start byte in the above multibyte keys. Handled in the code with a timeout.
410 {"\x1C", "^\\"}, // FS 410 {"\x1C", "^\\"}, // FS
411 {"\x1D", "^]"}, // GS 411 {"\x1D", "^]"}, // GS
412 {"\x1E", "^^"}, // RS 412 {"\x1E", "^^"}, // RS
413 {"\x1F", "^_"}, // US 413 {"\x1F", "^_"}, // US
414 {"\x7f", "BS"}, // Backspace key, usually. Ctrl-? perhaps? 414 {"\x7f", "BS"}, // Backspace key, usually. Ctrl-? perhaps?
415 {NULL, NULL} 415 {NULL, NULL}
416}; 416};
417 417
418char *borderChars[][6] = 418char *borderChars[][6] =
419{ 419{
420 {"-", "|", "+", "+", "+", "+"}, // "stick" characters. 420 {"-", "|", "+", "+", "+", "+"}, // "stick" characters.
421 {"\xE2\x94\x80", "\xE2\x94\x82", "\xE2\x94\x8C", "\xE2\x94\x90", "\xE2\x94\x94", "\xE2\x94\x98"}, // UTF-8 421 {"\xE2\x94\x80", "\xE2\x94\x82", "\xE2\x94\x8C", "\xE2\x94\x90", "\xE2\x94\x94", "\xE2\x94\x98"}, // UTF-8
422 {"\x71", "\x78", "\x6C", "\x6B", "\x6D", "\x6A"}, // VT100 alternate character set. 422 {"\x71", "\x78", "\x6C", "\x6B", "\x6D", "\x6A"}, // VT100 alternate character set.
423 {"\xC4", "\xB3", "\xDA", "\xBF", "\xC0", "\xD9"} // DOS 423 {"\xC4", "\xB3", "\xDA", "\xBF", "\xC0", "\xD9"} // DOS
424}; 424};
425 425
426char *borderCharsCurrent[][6] = 426char *borderCharsCurrent[][6] =
427{ 427{
428 {"=", "#", "+", "+", "+", "+"}, // "stick" characters. 428 {"=", "#", "+", "+", "+", "+"}, // "stick" characters.
429 {"\xE2\x95\x90", "\xE2\x95\x91", "\xE2\x95\x94", "\xE2\x95\x97", "\xE2\x95\x9A", "\xE2\x95\x9D"}, // UTF-8 429 {"\xE2\x95\x90", "\xE2\x95\x91", "\xE2\x95\x94", "\xE2\x95\x97", "\xE2\x95\x9A", "\xE2\x95\x9D"}, // UTF-8
430 {"\x71", "\x78", "\x6C", "\x6B", "\x6D", "\x6A"}, // VT100 alternate character set has none of these. B-( 430 {"\x71", "\x78", "\x6C", "\x6B", "\x6D", "\x6A"}, // VT100 alternate character set has none of these. B-(
431 {"\xCD", "\xBA", "\xC9", "\xBB", "\xC8", "\xBC"} // DOS 431 {"\xCD", "\xBA", "\xC9", "\xBB", "\xC8", "\xBC"} // DOS
432}; 432};
433 433
434 434
@@ -441,59 +441,59 @@ typedef void (*eventHandler) (view *view, event *event);
441 441
442struct function 442struct function
443{ 443{
444 char *name; // Name for script purposes. 444 char *name; // Name for script purposes.
445 char *description; // Human name for the menus. 445 char *description; // Human name for the menus.
446 char type; 446 char type;
447 union 447 union
448 { 448 {
449 eventHandler handler; 449 eventHandler handler;
450 char *scriptCallback; 450 char *scriptCallback;
451 }; 451 };
452}; 452};
453 453
454struct keyCommand 454struct keyCommand
455{ 455{
456 char *key; // Key name. 456 char *key; // Key name.
457 char *command; 457 char *command;
458}; 458};
459 459
460struct item 460struct item
461{ 461{
462 char *text; // What's shown to humans. 462 char *text; // What's shown to humans.
463 struct key *key; // Shortcut key while the menu is displayed. 463 struct key *key; // Shortcut key while the menu is displayed.
464 // If there happens to be a key bound to the same command, the menu system should find that and show it to. 464 // If there happens to be a key bound to the same command, the menu system should find that and show it to.
465 char type; 465 char type;
466 union 466 union
467 { 467 {
468 char *command; 468 char *command;
469 struct item *items; // An array of next level menu items. 469 struct item *items; // An array of next level menu items.
470 }; 470 };
471}; 471};
472 472
473struct borderWidget 473struct borderWidget
474{ 474{
475 char *text; 475 char *text;
476 char *command; 476 char *command;
477}; 477};
478 478
479// TODO - No idea if we will actually need this. 479// TODO - No idea if we will actually need this.
480struct _event 480struct _event
481{ 481{
482 struct function *function; 482 struct function *function;
483 uint16_t X, Y; // Current cursor position, or position of mouse click. 483 uint16_t X, Y; // Current cursor position, or position of mouse click.
484 char type; 484 char type;
485 union 485 union
486 { 486 {
487 struct keyCommand *key; // keystroke / mouse click 487 struct keyCommand *key; // keystroke / mouse click
488 struct item *item; // menu 488 struct item *item; // menu
489 struct borderWidget widget; // border widget click 489 struct borderWidget widget; // border widget click
490 int time; // timer 490 int time; // timer
491 struct // scroll contents 491 struct // scroll contents
492 { 492 {
493 int X, Y; 493 int X, Y;
494 } scroll; 494 } scroll;
495 // TODO - might need events for - leave box, enter box. Could use a new event type "command with arguments"? 495 // TODO - might need events for - leave box, enter box. Could use a new event type "command with arguments"?
496 }; 496 };
497}; 497};
498 498
499// TODO - a generic "part of text", and what is used to define them. 499// TODO - a generic "part of text", and what is used to define them.
@@ -502,33 +502,33 @@ struct _event
502 502
503struct mode 503struct mode
504{ 504{
505 struct keyCommand *keys; // An array of key to command mappings. 505 struct keyCommand *keys; // An array of key to command mappings.
506 struct item *items; // An array of top level menu items. 506 struct item *items; // An array of top level menu items.
507 struct item *functionKeys; // An array of single level "menus". Used to show key commands. 507 struct item *functionKeys; // An array of single level "menus". Used to show key commands.
508 uint8_t flags; // commandMode. 508 uint8_t flags; // commandMode.
509}; 509};
510 510
511/* 511/*
512Have a common menu up the top. 512Have a common menu up the top.
513 MC has a menu that changes per mode. 513 MC has a menu that changes per mode.
514 Nano has no menu. 514 Nano has no menu.
515Have a common display of certain keys down the bottom. 515Have a common display of certain keys down the bottom.
516 MC is one row of F1 to F10, but changes for edit / view / file browse. But those are contexts here. 516 MC is one row of F1 to F10, but changes for edit / view / file browse. But those are contexts here.
517 Nano is 12 random Ctrl keys, possibly in two lines, that changes depending on the editor mode, like editing the prompt line for various reasons, help. 517 Nano is 12 random Ctrl keys, possibly in two lines, that changes depending on the editor mode, like editing the prompt line for various reasons, help.
518*/ 518*/
519struct context // Defines a context for content. Text viewer, editor, file browser for instance. 519struct context // Defines a context for content. Text viewer, editor, file browser for instance.
520{ 520{
521 struct function *commands; // The master list, the ones pointed to by the menus etc should be in this list. 521 struct function *commands; // The master list, the ones pointed to by the menus etc should be in this list.
522 struct mode *modes; // A possible empty array of modes, indexed by the view. 522 struct mode *modes; // A possible empty array of modes, indexed by the view.
523 // OR might be better to have these as a linked list, so that things like Emacs can have it's mode keymap hierarcy. 523 // OR might be better to have these as a linked list, so that things like Emacs can have it's mode keymap hierarcy.
524 eventHandler handler; // TODO - Might be better to put this in the modes. I think vi will need that. 524 eventHandler handler; // TODO - Might be better to put this in the modes. I think vi will need that.
525 // Should set the damage list if it needs a redraw, and flags if border or status line needs updating. 525 // Should set the damage list if it needs a redraw, and flags if border or status line needs updating.
526 // Keyboard / mouse events if the box did not handle them itself. 526 // Keyboard / mouse events if the box did not handle them itself.
527 // DrawAll event for when drawing the box for the first time, on reveals for coming out of full screen, or user hit the redraw key. 527 // DrawAll event for when drawing the box for the first time, on reveals for coming out of full screen, or user hit the redraw key.
528 // Scroll event if the content wants to handle that itself. 528 // Scroll event if the content wants to handle that itself.
529 // Timer event for things like top that might want to have this called regularly. 529 // Timer event for things like top that might want to have this called regularly.
530 boxFunction doneRedraw; // The box is done with it's redraw, so we can free the damage list or whatever now. 530 boxFunction doneRedraw; // The box is done with it's redraw, so we can free the damage list or whatever now.
531 boxFunction delete; 531 boxFunction delete;
532 // This can be used as the sub struct for various context types. Like viewer, editor, file browser, top, etc. 532 // This can be used as the sub struct for various context types. Like viewer, editor, file browser, top, etc.
533 // Could even be an object hierarchy, like generic editor, which Basic vi inherits from. 533 // Could even be an object hierarchy, like generic editor, which Basic vi inherits from.
534 // Or not, since the commands might be different / more of them. 534 // Or not, since the commands might be different / more of them.
@@ -538,66 +538,66 @@ struct context // Defines a context for content. Text viewer, editor, file b
538// Status lines can have them to. 538// Status lines can have them to.
539struct border 539struct border
540{ 540{
541 struct borderWidget *topLeft; 541 struct borderWidget *topLeft;
542 struct borderWidget *topMiddle; 542 struct borderWidget *topMiddle;
543 struct borderWidget *topRight; 543 struct borderWidget *topRight;
544 struct borderWidget *bottomLeft; 544 struct borderWidget *bottomLeft;
545 struct borderWidget *bottomMiddle; 545 struct borderWidget *bottomMiddle;
546 struct borderWidget *bottomRight; 546 struct borderWidget *bottomRight;
547 struct borderWidget *left; 547 struct borderWidget *left;
548 struct borderWidget *right; 548 struct borderWidget *right;
549}; 549};
550 550
551struct line 551struct line
552{ 552{
553 struct line *next, *prev; 553 struct line *next, *prev;
554 uint32_t length; // Careful, this is the length of the allocated memory for real lines, but the number of lines in the header node. 554 uint32_t length; // Careful, this is the length of the allocated memory for real lines, but the number of lines in the header node.
555 char *line; // Should be blank for the header. 555 char *line; // Should be blank for the header.
556}; 556};
557 557
558struct damage 558struct damage
559{ 559{
560 struct damage *next; // A list for faster draws? 560 struct damage *next; // A list for faster draws?
561 uint16_t X, Y, W, H; // The rectangle to be redrawn. 561 uint16_t X, Y, W, H; // The rectangle to be redrawn.
562 uint16_t offset; // Offest from the left for showing lines. 562 uint16_t offset; // Offest from the left for showing lines.
563 struct line *lines; // Pointer to a list of text lines, or NULL. 563 struct line *lines; // Pointer to a list of text lines, or NULL.
564 // Note - likely a pointer into the middle of the line list in a content. 564 // Note - likely a pointer into the middle of the line list in a content.
565}; 565};
566 566
567struct content // For various instances of context types. 567struct content // For various instances of context types.
568 // Editor / text viewer might have several files open, so one of these per file. 568 // Editor / text viewer might have several files open, so one of these per file.
569 // MC might have several directories open, one of these per directory. No idea why you might want to do this. lol 569 // MC might have several directories open, one of these per directory. No idea why you might want to do this. lol
570{ 570{
571 struct context *context; 571 struct context *context;
572 char *name, *file, *path; 572 char *name, *file, *path;
573 struct line lines; 573 struct line lines;
574// file type 574// file type
575// double linked list of bookmarks, pointer to line, character position, length (or ending position?), type, blob for types to keep context. 575// double linked list of bookmarks, pointer to line, character position, length (or ending position?), type, blob for types to keep context.
576 uint16_t minW, minH, maxW, maxH; 576 uint16_t minW, minH, maxW, maxH;
577 uint8_t flags; // readOnly, modified. 577 uint8_t flags; // readOnly, modified.
578 // This can be used as the sub struct for various content types. 578 // This can be used as the sub struct for various content types.
579}; 579};
580 580
581struct _view 581struct _view
582{ 582{
583 struct content *content; 583 struct content *content;
584 box *box; 584 box *box;
585 struct border *border; // Can be NULL. 585 struct border *border; // Can be NULL.
586 char *statusLine; // Text of the status line, or NULL if none. 586 char *statusLine; // Text of the status line, or NULL if none.
587 int mode; // For those contexts that can be modal. Normally used to index the keys, menus, and key displays. 587 int mode; // For those contexts that can be modal. Normally used to index the keys, menus, and key displays.
588 struct damage *damage; // Can be NULL. If not NULL after context->doneRedraw(), box will free it and it's children. 588 struct damage *damage; // Can be NULL. If not NULL after context->doneRedraw(), box will free it and it's children.
589 // TODO - Gotta be careful of overlapping views. 589 // TODO - Gotta be careful of overlapping views.
590 void *data; // The context controls this blob, it's specific to each box. 590 void *data; // The context controls this blob, it's specific to each box.
591 uint32_t offsetX, offsetY; // Offset within the content, coz box handles scrolling, usually. 591 uint32_t offsetX, offsetY; // Offset within the content, coz box handles scrolling, usually.
592 uint16_t X, Y, W, H; // Position and size of the content area within the box. Calculated, but cached coz that might be needed for speed. 592 uint16_t X, Y, W, H; // Position and size of the content area within the box. Calculated, but cached coz that might be needed for speed.
593 uint16_t cX, cY; // Cursor position within the content. 593 uint16_t cX, cY; // Cursor position within the content.
594 uint16_t iX, oW; // Cursor position inside the lines input text, in case the formatter makes it different, and output length. 594 uint16_t iX, oW; // Cursor position inside the lines input text, in case the formatter makes it different, and output length.
595 char *output; // The current line formatted for output. 595 char *output; // The current line formatted for output.
596 uint8_t flags; // redrawStatus, redrawBorder; 596 uint8_t flags; // redrawStatus, redrawBorder;
597 597
598 // Assumption is that each box has it's own editLine (likely the line being edited), or that there's a box that is just the editLine (emacs minibuffer, and command lines for other proggies). 598 // Assumption is that each box has it's own editLine (likely the line being edited), or that there's a box that is just the editLine (emacs minibuffer, and command lines for other proggies).
599 struct line *line; // Pointer to the current line, might be the only line. 599 struct line *line; // Pointer to the current line, might be the only line.
600 char *prompt; // Optional prompt for the editLine. 600 char *prompt; // Optional prompt for the editLine.
601 601
602// Display mode / format hook. 602// Display mode / format hook.
603// view specific bookmarks, including highlighted block and it's type. 603// view specific bookmarks, including highlighted block and it's type.
@@ -607,13 +607,13 @@ struct _view
607 607
608struct _box 608struct _box
609{ 609{
610 box *sub1, *sub2, *parent; 610 box *sub1, *sub2, *parent;
611 view *view; // This boxes view into it's content. For sharing contents, like a split pane editor for instance, there might be more than one box with this content, but a different view. 611 view *view; // This boxes view into it's content. For sharing contents, like a split pane editor for instance, there might be more than one box with this content, but a different view.
612 // If it's just a parent box, it wont have this, so just make it a damn pointer, that's the simplest thing. lol 612 // If it's just a parent box, it wont have this, so just make it a damn pointer, that's the simplest thing. lol
613 // TODO - Are parent boxes getting a view anyway? 613 // TODO - Are parent boxes getting a view anyway?
614 uint16_t X, Y, W, H; // Position and size of the box itself, not the content. Calculated, but cached coz that might be needed for speed. 614 uint16_t X, Y, W, H; // Position and size of the box itself, not the content. Calculated, but cached coz that might be needed for speed.
615 float split; // Ratio of sub1's part of the split, the sub2 box gets the rest. 615 float split; // Ratio of sub1's part of the split, the sub2 box gets the rest.
616 uint8_t flags; // Various flags. 616 uint8_t flags; // Various flags.
617}; 617};
618 618
619 619
@@ -621,8 +621,8 @@ struct _box
621void drawBox(box *box); 621void drawBox(box *box);
622 622
623 623
624#define BOX_HSPLIT 1 // Marks if it's a horizontally or vertically split. 624#define BOX_HSPLIT 1 // Marks if it's a horizontally or vertically split.
625#define BOX_BORDER 2 // Mark if it has a border, often full screen boxes wont. 625#define BOX_BORDER 2 // Mark if it has a border, often full screen boxes wont.
626 626
627static box *rootBox; // Parent of the rest of the boxes, or the only box. Always a full screen. 627static box *rootBox; // Parent of the rest of the boxes, or the only box. Always a full screen.
628static box *currentBox; 628static box *currentBox;
@@ -631,91 +631,91 @@ static int commandMode;
631 631
632void doCommand(struct function *functions, char *command, view *view, event *event) 632void doCommand(struct function *functions, char *command, view *view, event *event)
633{ 633{
634 if (command) 634 if (command)
635 { 635 {
636 int i; 636 int i;
637 637
638 for (i = 0; functions[i].name; i++) 638 for (i = 0; functions[i].name; i++)
639 { 639 {
640 if (strcmp(functions[i].name, command) == 0) 640 if (strcmp(functions[i].name, command) == 0)
641 { 641 {
642 if (functions[i].handler); 642 if (functions[i].handler);
643 functions[i].handler(view, event); 643 functions[i].handler(view, event);
644 break; 644 break;
645 } 645 }
646 } 646 }
647 } 647 }
648} 648}
649 649
650// Inserts the line after the given line, or at the end of content if no line. 650// Inserts the line after the given line, or at the end of content if no line.
651struct line *addLine(struct content *content, struct line *line, char *text, uint32_t length) 651struct line *addLine(struct content *content, struct line *line, char *text, uint32_t length)
652{ 652{
653 struct line *result = NULL; 653 struct line *result = NULL;
654 uint32_t len; 654 uint32_t len;
655 655
656 if (!length) 656 if (!length)
657 length = strlen(text); 657 length = strlen(text);
658 // Round length up. 658 // Round length up.
659 len = (((length + 1) / MEM_SIZE) + 1) * MEM_SIZE; 659 len = (((length + 1) / MEM_SIZE) + 1) * MEM_SIZE;
660 result = xzalloc(sizeof(struct line)); 660 result = xzalloc(sizeof(struct line));
661 result->line = xzalloc(len); 661 result->line = xzalloc(len);
662 result->length = len; 662 result->length = len;
663 strncpy(result->line, text, length); 663 strncpy(result->line, text, length);
664 664
665 if (content) 665 if (content)
666 { 666 {
667 if (!line) 667 if (!line)
668 line = content->lines.prev; 668 line = content->lines.prev;
669 669
670 result->next = line->next; 670 result->next = line->next;
671 result->prev = line; 671 result->prev = line;
672 672
673 line->next->prev = result; 673 line->next->prev = result;
674 line->next = result; 674 line->next = result;
675 675
676 content->lines.length++; 676 content->lines.length++;
677 } 677 }
678 else 678 else
679 { 679 {
680 result->next = result; 680 result->next = result;
681 result->prev = result; 681 result->prev = result;
682 } 682 }
683 683
684 return result; 684 return result;
685} 685}
686 686
687void freeLine(struct content *content, struct line *line) 687void freeLine(struct content *content, struct line *line)
688{ 688{
689 line->next->prev = line->prev; 689 line->next->prev = line->prev;
690 line->prev->next = line->next; 690 line->prev->next = line->next;
691 if (content) 691 if (content)
692 content->lines.length--; 692 content->lines.length--;
693 free(line->line); 693 free(line->line);
694 free(line); 694 free(line);
695} 695}
696 696
697void loadFile(struct content *content) 697void loadFile(struct content *content)
698{ 698{
699 int fd = open(content->path, O_RDONLY); 699 int fd = open(content->path, O_RDONLY);
700 700
701 if (-1 != fd) 701 if (-1 != fd)
702 { 702 {
703 char *temp = NULL; 703 char *temp = NULL;
704 long len; 704 long len;
705 705
706 do 706 do
707 { 707 {
708 // TODO - get_rawline() is slow, and wont help much with DOS and Mac line endings. 708 // TODO - get_rawline() is slow, and wont help much with DOS and Mac line endings.
709 temp = get_rawline(fd, &len, '\n'); 709 temp = get_rawline(fd, &len, '\n');
710 if (temp) 710 if (temp)
711 { 711 {
712 if (temp[len - 1] == '\n') 712 if (temp[len - 1] == '\n')
713 temp[--len] = '\0'; 713 temp[--len] = '\0';
714 addLine(content, NULL, temp, len); 714 addLine(content, NULL, temp, len);
715 } 715 }
716 } while (temp); 716 } while (temp);
717 close(fd); 717 close(fd);
718 } 718 }
719} 719}
720 720
721// TODO - load and save should be able to deal with pipes, and with loading only parts of files, to load more parts later. 721// TODO - load and save should be able to deal with pipes, and with loading only parts of files, to load more parts later.
@@ -723,45 +723,45 @@ void loadFile(struct content *content)
723void saveFile(struct content *content) 723void saveFile(struct content *content)
724{ 724{
725// TODO - Should do "Save as" as well. Which is just a matter of changing content->path before calling this. 725// TODO - Should do "Save as" as well. Which is just a matter of changing content->path before calling this.
726 int fd; 726 int fd;
727 727
728 fd = open(content->path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); 728 fd = open(content->path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
729 729
730 if (-1 != fd) 730 if (-1 != fd)
731 { 731 {
732 struct line *line = content->lines.next; 732 struct line *line = content->lines.next;
733 733
734 while (&(content->lines) != line) // We are at the end if we have wrapped to the beginning. 734 while (&(content->lines) != line) // We are at the end if we have wrapped to the beginning.
735 { 735 {
736 write(fd, line->line, strlen(line->line)); 736 write(fd, line->line, strlen(line->line));
737 write(fd, "\n", 1); 737 write(fd, "\n", 1);
738 line = line->next; 738 line = line->next;
739 } 739 }
740 close(fd); 740 close(fd);
741 } 741 }
742 else 742 else
743 { 743 {
744 fprintf(stderr, "Can't open file %s\n", content->path); 744 fprintf(stderr, "Can't open file %s\n", content->path);
745 exit(1); 745 exit(1);
746 } 746 }
747} 747}
748 748
749struct content *addContent(char *name, struct context *context, char *filePath) 749struct content *addContent(char *name, struct context *context, char *filePath)
750{ 750{
751 struct content *result = xzalloc(sizeof(struct content)); 751 struct content *result = xzalloc(sizeof(struct content));
752 752
753 result->lines.next = &(result->lines); 753 result->lines.next = &(result->lines);
754 result->lines.prev = &(result->lines); 754 result->lines.prev = &(result->lines);
755 result->name = strdup(name); 755 result->name = strdup(name);
756 result->context = context; 756 result->context = context;
757 757
758 if (filePath) 758 if (filePath)
759 { 759 {
760 result->path = strdup(filePath); 760 result->path = strdup(filePath);
761 loadFile(result); 761 loadFile(result);
762 } 762 }
763 763
764 return result; 764 return result;
765} 765}
766 766
767// General purpose line moosher. Used for appends, inserts, overwrites, and deletes. 767// General purpose line moosher. Used for appends, inserts, overwrites, and deletes.
@@ -774,73 +774,73 @@ void mooshLines(struct content *content, struct line *result, struct line *moosh
774// General purpose string moosher. Used for appends, inserts, overwrites, and deletes. 774// General purpose string moosher. Used for appends, inserts, overwrites, and deletes.
775void mooshStrings(struct line *result, char *moosh, uint16_t index, uint16_t length, int insert) 775void mooshStrings(struct line *result, char *moosh, uint16_t index, uint16_t length, int insert)
776{ 776{
777 char *c, *pos; 777 char *c, *pos;
778 int limit = strlen(result->line); 778 int limit = strlen(result->line);
779 int mooshLen = 0, resultLen; 779 int mooshLen = 0, resultLen;
780 780
781 if (moosh) 781 if (moosh)
782 mooshLen = strlen(moosh); 782 mooshLen = strlen(moosh);
783 783
784 /* 784 /*
785 * moosh == NULL a deletion 785 * moosh == NULL a deletion
786 * length == 0 simple insertion 786 * length == 0 simple insertion
787 * length < mooshlen delete some, insert moosh 787 * length < mooshlen delete some, insert moosh
788 * length == mooshlen exact overwrite. 788 * length == mooshlen exact overwrite.
789 * length > mooshlen delete a lot, insert moosh 789 * length > mooshlen delete a lot, insert moosh
790 */ 790 */
791 791
792 mooshLen -= length; 792 mooshLen -= length;
793 resultLen = limit + mooshLen; 793 resultLen = limit + mooshLen;
794 794
795 // If we need more space, allocate more. 795 // If we need more space, allocate more.
796 if (resultLen > result->length) 796 if (resultLen > result->length)
797 { 797 {
798 result->length = resultLen + MEM_SIZE; 798 result->length = resultLen + MEM_SIZE;
799 result->line = xrealloc(result->line, result->length); 799 result->line = xrealloc(result->line, result->length);
800 } 800 }
801 801
802 if (limit <= index) // At end, just add to end. 802 if (limit <= index) // At end, just add to end.
803 { 803 {
804 // TODO - Possibly add spaces to pad out to where index is? 804 // TODO - Possibly add spaces to pad out to where index is?
805 // Would be needed for "go beyond end of line" and "column blocks". 805 // Would be needed for "go beyond end of line" and "column blocks".
806 // Both of those are advanced editing. 806 // Both of those are advanced editing.
807 index = limit; 807 index = limit;
808 insert = 1; 808 insert = 1;
809 } 809 }
810 810
811 pos = &(result->line[index]); 811 pos = &(result->line[index]);
812 812
813 if (insert) // Insert / delete before current character, so move it and the rest up / down mooshLen bytes. 813 if (insert) // Insert / delete before current character, so move it and the rest up / down mooshLen bytes.
814 { 814 {
815 if (0 < mooshLen) // Gotta move things up. 815 if (0 < mooshLen) // Gotta move things up.
816 { 816 {
817 c = &(result->line[limit]); 817 c = &(result->line[limit]);
818 while (c >= pos) 818 while (c >= pos)
819 { 819 {
820 *(c + mooshLen) = *c; 820 *(c + mooshLen) = *c;
821 c--; 821 c--;
822 } 822 }
823 } 823 }
824 else if (0 > mooshLen) // Gotta move things down. 824 else if (0 > mooshLen) // Gotta move things down.
825 { 825 {
826 c = pos; 826 c = pos;
827 while (*c) 827 while (*c)
828 { 828 {
829 *c = *(c - mooshLen); // A double negative. 829 *c = *(c - mooshLen); // A double negative.
830 c++; 830 c++;
831 } 831 }
832 } 832 }
833 } 833 }
834 834
835 if (moosh) 835 if (moosh)
836 { 836 {
837 c = moosh; 837 c = moosh;
838 do 838 do
839 { 839 {
840 *pos++ = *c++; 840 *pos++ = *c++;
841 } 841 }
842 while (*c); 842 while (*c);
843 } 843 }
844} 844}
845 845
846// TODO - Should draw the current border in green, the text as default (or highlight / bright). 846// TODO - Should draw the current border in green, the text as default (or highlight / bright).
@@ -848,83 +848,83 @@ void mooshStrings(struct line *result, char *moosh, uint16_t index, uint16_t len
848// All other boxes with dark gray border, and dim text. 848// All other boxes with dark gray border, and dim text.
849void drawLine(int y, int start, int end, char *left, char *internal, char *contents, char *right, int current) 849void drawLine(int y, int start, int end, char *left, char *internal, char *contents, char *right, int current)
850{ 850{
851 int size = strlen(internal); 851 int size = strlen(internal);
852 int len = (end - start) * size, x = 0; 852 int len = (end - start) * size, x = 0;
853 char line[len + 1]; 853 char line[len + 1];
854 854
855 if ('\0' != left[0]) // Assumes that if one side has a border, then so does the other. 855 if ('\0' != left[0]) // Assumes that if one side has a border, then so does the other.
856 len -= 2 * size; 856 len -= 2 * size;
857 857
858 if (contents) 858 if (contents)
859 { 859 {
860 // strncpy wont add a null at the end if the source is longer, but will pad with nulls if source is shorter. 860 // strncpy wont add a null at the end if the source is longer, but will pad with nulls if source is shorter.
861 // So it's best to put a safety null in first. 861 // So it's best to put a safety null in first.
862 line[len] = '\0'; 862 line[len] = '\0';
863 strncpy(line, contents, len); 863 strncpy(line, contents, len);
864 // Make sure the following while loop pads out line with the internal character. 864 // Make sure the following while loop pads out line with the internal character.
865 x = strlen(line); 865 x = strlen(line);
866 } 866 }
867 while (x < len) 867 while (x < len)
868 { 868 {
869 strcpy(&line[x], internal); 869 strcpy(&line[x], internal);
870 x += size; 870 x += size;
871 } 871 }
872 line[x++] = '\0'; 872 line[x++] = '\0';
873 if ('\0' == left[0]) // Assumes that if one side has a border, then so does the other. 873 if ('\0' == left[0]) // Assumes that if one side has a border, then so does the other.
874 { 874 {
875 if (current) 875 if (current)
876 printf("\x1B[1m\x1B[%d;%dH%s\x1B[m", y + 1, start + 1, line); 876 printf("\x1B[1m\x1B[%d;%dH%s\x1B[m", y + 1, start + 1, line);
877 else 877 else
878 printf("\x1B[m\x1B[%d;%dH%s", y + 1, start + 1, line); 878 printf("\x1B[m\x1B[%d;%dH%s", y + 1, start + 1, line);
879 } 879 }
880 else 880 else
881 { 881 {
882 if (current) 882 if (current)
883 printf("\x1B[1m\x1B[%d;%dH%s%s%s\x1B[m", y + 1, start + 1, left, line, right); 883 printf("\x1B[1m\x1B[%d;%dH%s%s%s\x1B[m", y + 1, start + 1, left, line, right);
884 else 884 else
885 printf("\x1B[m\x1B[%d;%dH%s%s%s", y + 1, start + 1, left, line, right); 885 printf("\x1B[m\x1B[%d;%dH%s%s%s", y + 1, start + 1, left, line, right);
886 } 886 }
887} 887}
888 888
889void formatCheckCursor(view *view, long *cX, long *cY, char *input) 889void formatCheckCursor(view *view, long *cX, long *cY, char *input)
890{ 890{
891 int i = 0, o = 0, direction = (*cX) - view->cX; 891 int i = 0, o = 0, direction = (*cX) - view->cX;
892 892
893 // Adjust the cursor if needed, depending on the contents of the line, and the direction of travel. 893 // Adjust the cursor if needed, depending on the contents of the line, and the direction of travel.
894 while (input[i]) 894 while (input[i])
895 { 895 {
896 // When o is equal to the cX position, update the iX position to be where i is. 896 // When o is equal to the cX position, update the iX position to be where i is.
897 if ('\t' == input[i]) 897 if ('\t' == input[i])
898 { 898 {
899 int j = 8 - (i % 8); 899 int j = 8 - (i % 8);
900 900
901 // Check if the cursor is in the middle of the tab. 901 // Check if the cursor is in the middle of the tab.
902 if (((*cX) > o) && ((*cX) < (o + j))) 902 if (((*cX) > o) && ((*cX) < (o + j)))
903 { 903 {
904 if (0 <= direction) 904 if (0 <= direction)
905 { 905 {
906 *cX = (o + j); 906 *cX = (o + j);
907 view->iX = i + 1; 907 view->iX = i + 1;
908 } 908 }
909 else 909 else
910 { 910 {
911 *cX = o; 911 *cX = o;
912 view->iX = i; 912 view->iX = i;
913 } 913 }
914 } 914 }
915 o += j; 915 o += j;
916 } 916 }
917 else 917 else
918 { 918 {
919 if ((*cX) == o) 919 if ((*cX) == o)
920 view->iX = i; 920 view->iX = i;
921 o++; 921 o++;
922 } 922 }
923 i++; 923 i++;
924 } 924 }
925 // One more check in case the cursor is at the end of the line. 925 // One more check in case the cursor is at the end of the line.
926 if ((*cX) == o) 926 if ((*cX) == o)
927 view->iX = i; 927 view->iX = i;
928} 928}
929 929
930// TODO - Should convert control characters to reverse video, and deal with UTF8. 930// TODO - Should convert control characters to reverse video, and deal with UTF8.
@@ -1004,566 +1004,566 @@ Thanks for reporting it Roy.
1004 1004
1005int formatLine(view *view, char *input, char **output) 1005int formatLine(view *view, char *input, char **output)
1006{ 1006{
1007 int len = strlen(input), i = 0, o = 0; 1007 int len = strlen(input), i = 0, o = 0;
1008 1008
1009 *output = xrealloc(*output, len + 1); 1009 *output = xrealloc(*output, len + 1);
1010 1010
1011 while (input[i]) 1011 while (input[i])
1012 { 1012 {
1013 if ('\t' == input[i]) 1013 if ('\t' == input[i])
1014 { 1014 {
1015 int j = 8 - (i % 8); 1015 int j = 8 - (i % 8);
1016 1016
1017 *output = xrealloc(*output, len + j + 1); 1017 *output = xrealloc(*output, len + j + 1);
1018 for (; j; j--) 1018 for (; j; j--)
1019 { 1019 {
1020 (*output)[o++] = ' '; 1020 (*output)[o++] = ' ';
1021 len++; 1021 len++;
1022 } 1022 }
1023 len--; // Not counting the actual tab character itself. 1023 len--; // Not counting the actual tab character itself.
1024 } 1024 }
1025 else 1025 else
1026 (*output)[o++] = input[i]; 1026 (*output)[o++] = input[i];
1027 i++; 1027 i++;
1028 } 1028 }
1029 (*output)[o++] = '\0'; 1029 (*output)[o++] = '\0';
1030 1030
1031 return len; 1031 return len;
1032} 1032}
1033 1033
1034void drawContentLine(view *view, int y, int start, int end, char *left, char *internal, char *contents, char *right, int current) 1034void drawContentLine(view *view, int y, int start, int end, char *left, char *internal, char *contents, char *right, int current)
1035{ 1035{
1036 char *temp = NULL; 1036 char *temp = NULL;
1037 int offset = view->offsetX, len; 1037 int offset = view->offsetX, len;
1038 1038
1039 if (contents == view->line->line) 1039 if (contents == view->line->line)
1040 { 1040 {
1041 view->oW = formatLine(view, contents, &(view->output)); 1041 view->oW = formatLine(view, contents, &(view->output));
1042 temp = view->output; 1042 temp = view->output;
1043 len = view->oW; 1043 len = view->oW;
1044 } 1044 }
1045 else // Only time we are not drawing the current line, and only used for drawing the entire page. 1045 else // Only time we are not drawing the current line, and only used for drawing the entire page.
1046 len = formatLine(NULL, contents, &(temp)); 1046 len = formatLine(NULL, contents, &(temp));
1047 1047
1048 if (offset > len) 1048 if (offset > len)
1049 offset = len; 1049 offset = len;
1050 drawLine(y, start, end, left, internal, &(temp[offset]), right, current); 1050 drawLine(y, start, end, left, internal, &(temp[offset]), right, current);
1051} 1051}
1052 1052
1053int moveCursorAbsolute(view *view, long cX, long cY, long sX, long sY) 1053int moveCursorAbsolute(view *view, long cX, long cY, long sX, long sY)
1054{ 1054{
1055 struct line *newLine = view->line; 1055 struct line *newLine = view->line;
1056 long oX = view->offsetX, oY = view->offsetY; 1056 long oX = view->offsetX, oY = view->offsetY;
1057 long lX = view->oW, lY = view->content->lines.length - 1; 1057 long lX = view->oW, lY = view->content->lines.length - 1;
1058 long nY = view->cY; 1058 long nY = view->cY;
1059 uint16_t w = view->W - 1, h = view->H - 1; 1059 uint16_t w = view->W - 1, h = view->H - 1;
1060 int moved = 0, updatedY = 0, endOfLine = 0; 1060 int moved = 0, updatedY = 0, endOfLine = 0;
1061 1061
1062 // Check if it's still within the contents. 1062 // Check if it's still within the contents.
1063 if (0 > cY) // Trying to move before the beginning of the content. 1063 if (0 > cY) // Trying to move before the beginning of the content.
1064 cY = 0; 1064 cY = 0;
1065 else if (lY < cY) // Trying to move beyond end of the content. 1065 else if (lY < cY) // Trying to move beyond end of the content.
1066 cY = lY; 1066 cY = lY;
1067 if (0 > cX) // Trying to move before the beginning of the line. 1067 if (0 > cX) // Trying to move before the beginning of the line.
1068 { 1068 {
1069 // See if we can move to the end of the previous line. 1069 // See if we can move to the end of the previous line.
1070 if (view->line->prev != &(view->content->lines)) 1070 if (view->line->prev != &(view->content->lines))
1071 { 1071 {
1072 cY--; 1072 cY--;
1073 endOfLine = 1; 1073 endOfLine = 1;
1074 } 1074 }
1075 else 1075 else
1076 cX = 0; 1076 cX = 0;
1077 } 1077 }
1078 else if (lX < cX) // Trying to move beyond end of line. 1078 else if (lX < cX) // Trying to move beyond end of line.
1079 { 1079 {
1080 // See if we can move to the begining of the next line. 1080 // See if we can move to the begining of the next line.
1081 if (view->line->next != &(view->content->lines)) 1081 if (view->line->next != &(view->content->lines))
1082 { 1082 {
1083 cY++; 1083 cY++;
1084 cX = 0; 1084 cX = 0;
1085 } 1085 }
1086 else 1086 else
1087 cX = lX; 1087 cX = lX;
1088 } 1088 }
1089 1089
1090 // Find the new line. 1090 // Find the new line.
1091 while (nY != cY) 1091 while (nY != cY)
1092 { 1092 {
1093 updatedY = 1; 1093 updatedY = 1;
1094 if (nY < cY) 1094 if (nY < cY)
1095 { 1095 {
1096 newLine = newLine->next; 1096 newLine = newLine->next;
1097 nY++; 1097 nY++;
1098 if (view->content->lines.prev == newLine) // We are at the end if we have wrapped to the beginning. 1098 if (view->content->lines.prev == newLine) // We are at the end if we have wrapped to the beginning.
1099 break; 1099 break;
1100 } 1100 }
1101 else 1101 else
1102 { 1102 {
1103 newLine = newLine->prev; 1103 newLine = newLine->prev;
1104 nY--; 1104 nY--;
1105 if (view->content->lines.next == newLine) // We are at the end if we have wrapped to the beginning. 1105 if (view->content->lines.next == newLine) // We are at the end if we have wrapped to the beginning.
1106 break; 1106 break;
1107 } 1107 }
1108 } 1108 }
1109 cY = nY; 1109 cY = nY;
1110 1110
1111 // Check if we have moved past the end of the new line. 1111 // Check if we have moved past the end of the new line.
1112 if (updatedY) 1112 if (updatedY)
1113 { 1113 {
1114 // Format it. 1114 // Format it.
1115 view->oW = formatLine(view, newLine->line, &(view->output)); 1115 view->oW = formatLine(view, newLine->line, &(view->output));
1116 if (view->oW < cX) 1116 if (view->oW < cX)
1117 endOfLine = 1; 1117 endOfLine = 1;
1118 if (endOfLine) 1118 if (endOfLine)
1119 cX = view->oW; 1119 cX = view->oW;
1120 } 1120 }
1121 1121
1122 // Let the formatter decide if it wants to adjust things. 1122 // Let the formatter decide if it wants to adjust things.
1123 // It's up to the formatter to deal with things if it changes cY. 1123 // It's up to the formatter to deal with things if it changes cY.
1124 // On the other hand, changing cX is it's job. 1124 // On the other hand, changing cX is it's job.
1125 formatCheckCursor(view, &cX, &cY, newLine->line); 1125 formatCheckCursor(view, &cX, &cY, newLine->line);
1126 1126
1127 // Check the scrolling. 1127 // Check the scrolling.
1128 lY -= view->H - 1; 1128 lY -= view->H - 1;
1129 oX += sX; 1129 oX += sX;
1130 oY += sY; 1130 oY += sY;
1131 1131
1132 if (oY > cY) // Trying to move above the box. 1132 if (oY > cY) // Trying to move above the box.
1133 oY += cY - oY; 1133 oY += cY - oY;
1134 else if ((oY + h) < cY) // Trying to move below the box 1134 else if ((oY + h) < cY) // Trying to move below the box
1135 oY += cY - (oY + h); 1135 oY += cY - (oY + h);
1136 if (oX > cX) // Trying to move to the left of the box. 1136 if (oX > cX) // Trying to move to the left of the box.
1137 oX += cX - oX; 1137 oX += cX - oX;
1138 else if ((oX + w) <= cX) // Trying to move to the right of the box. 1138 else if ((oX + w) <= cX) // Trying to move to the right of the box.
1139 oX += cX - (oX + w); 1139 oX += cX - (oX + w);
1140 1140
1141 if (oY < 0) 1141 if (oY < 0)
1142 oY = 0; 1142 oY = 0;
1143 if (oY >= lY) 1143 if (oY >= lY)
1144 oY = lY; 1144 oY = lY;
1145 if (oX < 0) 1145 if (oX < 0)
1146 oX = 0; 1146 oX = 0;
1147 // TODO - Should limit oX to less than the longest line, minus box width. 1147 // TODO - Should limit oX to less than the longest line, minus box width.
1148 // Gonna be a pain figuring out what the longest line is. 1148 // Gonna be a pain figuring out what the longest line is.
1149 // On the other hand, don't think that will be an actual issue unless "move past end of line" is enabled, and that's an advanced editor thing. 1149 // On the other hand, don't think that will be an actual issue unless "move past end of line" is enabled, and that's an advanced editor thing.
1150 // Though still might want to do that for the longest line on the new page to be. 1150 // Though still might want to do that for the longest line on the new page to be.
1151 1151
1152 if ((view->cX != cX) || (view->cY != cY)) 1152 if ((view->cX != cX) || (view->cY != cY))
1153 moved = 1; 1153 moved = 1;
1154 1154
1155 // Actually update stuff, though some have been done already. 1155 // Actually update stuff, though some have been done already.
1156 view->cX = cX; 1156 view->cX = cX;
1157 view->cY = cY; 1157 view->cY = cY;
1158 view->line = newLine; 1158 view->line = newLine;
1159 1159
1160 // Handle scrolling. 1160 // Handle scrolling.
1161 if ((view->offsetX != oX) || (view->offsetY != oY)) 1161 if ((view->offsetX != oX) || (view->offsetY != oY))
1162 { 1162 {
1163 view->offsetX = oX; 1163 view->offsetX = oX;
1164 view->offsetY = oY; 1164 view->offsetY = oY;
1165 1165
1166 if (view->box) 1166 if (view->box)
1167 drawBox(view->box); 1167 drawBox(view->box);
1168 } 1168 }
1169 1169
1170 return moved; 1170 return moved;
1171} 1171}
1172 1172
1173int moveCursorRelative(view *view, long cX, long cY, long sX, long sY) 1173int moveCursorRelative(view *view, long cX, long cY, long sX, long sY)
1174{ 1174{
1175 return moveCursorAbsolute(view, view->cX + cX, view->cY + cY, sX, sY); 1175 return moveCursorAbsolute(view, view->cX + cX, view->cY + cY, sX, sY);
1176} 1176}
1177 1177
1178void sizeViewToBox(box *box, int X, int Y, int W, int H) 1178void sizeViewToBox(box *box, int X, int Y, int W, int H)
1179{ 1179{
1180 uint16_t one = 1, two = 2; 1180 uint16_t one = 1, two = 2;
1181 1181
1182 if (!(box->flags & BOX_BORDER)) 1182 if (!(box->flags & BOX_BORDER))
1183 { 1183 {
1184 one = 0; 1184 one = 0;
1185 two = 0; 1185 two = 0;
1186 } 1186 }
1187 box->view->X = X; 1187 box->view->X = X;
1188 box->view->Y = Y; 1188 box->view->Y = Y;
1189 box->view->W = W; 1189 box->view->W = W;
1190 box->view->H = H; 1190 box->view->H = H;
1191 if (0 > X) box->view->X = box->X + one; 1191 if (0 > X) box->view->X = box->X + one;
1192 if (0 > Y) box->view->Y = box->Y + one; 1192 if (0 > Y) box->view->Y = box->Y + one;
1193 if (0 > W) box->view->W = box->W - two; 1193 if (0 > W) box->view->W = box->W - two;
1194 if (0 > H) box->view->H = box->H - two; 1194 if (0 > H) box->view->H = box->H - two;
1195} 1195}
1196 1196
1197view *addView(char *name, struct context *context, char *filePath, uint16_t X, uint16_t Y, uint16_t W, uint16_t H) 1197view *addView(char *name, struct context *context, char *filePath, uint16_t X, uint16_t Y, uint16_t W, uint16_t H)
1198{ 1198{
1199 view *result = xzalloc(sizeof(struct _view)); 1199 view *result = xzalloc(sizeof(struct _view));
1200 1200
1201 result->X = X; 1201 result->X = X;
1202 result->Y = Y; 1202 result->Y = Y;
1203 result->W = W; 1203 result->W = W;
1204 result->H = H; 1204 result->H = H;
1205 1205
1206 result->content = addContent(name, context, filePath); 1206 result->content = addContent(name, context, filePath);
1207 result->prompt = xzalloc(1); 1207 result->prompt = xzalloc(1);
1208 // If there was content, format it's first line as usual, otherwise create an empty first line. 1208 // If there was content, format it's first line as usual, otherwise create an empty first line.
1209 if (result->content->lines.next != &(result->content->lines)) 1209 if (result->content->lines.next != &(result->content->lines))
1210 { 1210 {
1211 result->line = result->content->lines.next; 1211 result->line = result->content->lines.next;
1212 result->oW = formatLine(result, result->line->line, &(result->output)); 1212 result->oW = formatLine(result, result->line->line, &(result->output));
1213 } 1213 }
1214 else 1214 else
1215 { 1215 {
1216 result->line = addLine(result->content, NULL, "\0", 0); 1216 result->line = addLine(result->content, NULL, "\0", 0);
1217 result->output = xzalloc(1); 1217 result->output = xzalloc(1);
1218 } 1218 }
1219 1219
1220 return result; 1220 return result;
1221} 1221}
1222 1222
1223box *addBox(char *name, struct context *context, char *filePath, uint16_t X, uint16_t Y, uint16_t W, uint16_t H) 1223box *addBox(char *name, struct context *context, char *filePath, uint16_t X, uint16_t Y, uint16_t W, uint16_t H)
1224{ 1224{
1225 box *result = xzalloc(sizeof(struct _box)); 1225 box *result = xzalloc(sizeof(struct _box));
1226 1226
1227 result->X = X; 1227 result->X = X;
1228 result->Y = Y; 1228 result->Y = Y;
1229 result->W = W; 1229 result->W = W;
1230 result->H = H; 1230 result->H = H;
1231 result->view = addView(name, context, filePath, X, Y, W, H); 1231 result->view = addView(name, context, filePath, X, Y, W, H);
1232 result->view->box = result; 1232 result->view->box = result;
1233 sizeViewToBox(result, X, Y, W, H); 1233 sizeViewToBox(result, X, Y, W, H);
1234 1234
1235 return result; 1235 return result;
1236} 1236}
1237 1237
1238void freeBox(box *box) 1238void freeBox(box *box)
1239{ 1239{
1240 if (box) 1240 if (box)
1241 { 1241 {
1242 freeBox(box->sub1); 1242 freeBox(box->sub1);
1243 freeBox(box->sub2); 1243 freeBox(box->sub2);
1244 if (box->view) 1244 if (box->view)
1245 { 1245 {
1246 // In theory the line should not be part of the content if there is no content, so we should free it. 1246 // In theory the line should not be part of the content if there is no content, so we should free it.
1247 if (!box->view->content) 1247 if (!box->view->content)
1248 freeLine(NULL, box->view->line); 1248 freeLine(NULL, box->view->line);
1249 free(box->view->prompt); 1249 free(box->view->prompt);
1250 free(box->view->output); 1250 free(box->view->output);
1251 free(box->view); 1251 free(box->view);
1252 } 1252 }
1253 free(box); 1253 free(box);
1254 } 1254 }
1255} 1255}
1256 1256
1257void drawBox(box *box) 1257void drawBox(box *box)
1258{ 1258{
1259 // This could be heavily optimized, but let's keep things simple for now. 1259 // This could be heavily optimized, but let's keep things simple for now.
1260 // Optimized for sending less characters I mean, on slow serial links for instance. 1260 // Optimized for sending less characters I mean, on slow serial links for instance.
1261 1261
1262 char **bchars = (toys.optflags & FLAG_a) ? borderChars[0] : borderChars[1]; 1262 char **bchars = (toys.optflags & FLAG_a) ? borderChars[0] : borderChars[1];
1263 char *left = "\0", *right = "\0"; 1263 char *left = "\0", *right = "\0";
1264 struct line *lines = NULL; 1264 struct line *lines = NULL;
1265 int y = box->Y, current = (box == currentBox); 1265 int y = box->Y, current = (box == currentBox);
1266 uint16_t h = box->Y + box->H; 1266 uint16_t h = box->Y + box->H;
1267 1267
1268 if (current) 1268 if (current)
1269 bchars = (toys.optflags & FLAG_a) ? borderCharsCurrent[0] : borderCharsCurrent[1]; 1269 bchars = (toys.optflags & FLAG_a) ? borderCharsCurrent[0] : borderCharsCurrent[1];
1270 1270
1271 // Slow and laborious way to figure out where in the linked list of lines we start from. 1271 // Slow and laborious way to figure out where in the linked list of lines we start from.
1272 // Wont scale well, but is simple. 1272 // Wont scale well, but is simple.
1273 if (box->view && box->view->content) 1273 if (box->view && box->view->content)
1274 { 1274 {
1275 int i = box->view->offsetY; 1275 int i = box->view->offsetY;
1276 1276
1277 lines = &(box->view->content->lines); 1277 lines = &(box->view->content->lines);
1278 while (i--) 1278 while (i--)
1279 { 1279 {
1280 lines = lines->next; 1280 lines = lines->next;
1281 if (&(box->view->content->lines) == lines) // We are at the end if we have wrapped to the beginning. 1281 if (&(box->view->content->lines) == lines) // We are at the end if we have wrapped to the beginning.
1282 break; 1282 break;
1283 } 1283 }
1284 } 1284 }
1285 1285
1286 if (box->flags & BOX_BORDER) 1286 if (box->flags & BOX_BORDER)
1287 { 1287 {
1288 h--; 1288 h--;
1289 left = right = bchars[1]; 1289 left = right = bchars[1];
1290 drawLine(y++, box->X, box->X + box->W, bchars[2], bchars[0], NULL, bchars[3], current); 1290 drawLine(y++, box->X, box->X + box->W, bchars[2], bchars[0], NULL, bchars[3], current);
1291 } 1291 }
1292 1292
1293 while (y < h) 1293 while (y < h)
1294 { 1294 {
1295 char *line = ""; 1295 char *line = "";
1296 1296
1297 if (lines) 1297 if (lines)
1298 { 1298 {
1299 lines = lines->next; 1299 lines = lines->next;
1300 if (&(box->view->content->lines) == lines) // We are at the end if we have wrapped to the beginning. 1300 if (&(box->view->content->lines) == lines) // We are at the end if we have wrapped to the beginning.
1301 lines = NULL; 1301 lines = NULL;
1302 else 1302 else
1303 line = lines->line; 1303 line = lines->line;
1304 // Figure out which line is our current line while we are here. 1304 // Figure out which line is our current line while we are here.
1305 if (box->view->Y + (box->view->cY - box->view->offsetY) == y) 1305 if (box->view->Y + (box->view->cY - box->view->offsetY) == y)
1306 box->view->line = lines; 1306 box->view->line = lines;
1307 } 1307 }
1308 drawContentLine(box->view, y++, box->X, box->X + box->W, left, " ", line, right, current); 1308 drawContentLine(box->view, y++, box->X, box->X + box->W, left, " ", line, right, current);
1309 } 1309 }
1310 if (box->flags & BOX_BORDER) 1310 if (box->flags & BOX_BORDER)
1311 drawLine(y++, box->X, box->X + box->W, bchars[4], bchars[0], NULL, bchars[5], current); 1311 drawLine(y++, box->X, box->X + box->W, bchars[4], bchars[0], NULL, bchars[5], current);
1312 fflush(stdout); 1312 fflush(stdout);
1313} 1313}
1314 1314
1315void drawBoxes(box *box) 1315void drawBoxes(box *box)
1316{ 1316{
1317 if (box->sub1) // If there's one sub box, there's always two. 1317 if (box->sub1) // If there's one sub box, there's always two.
1318 { 1318 {
1319 drawBoxes(box->sub1); 1319 drawBoxes(box->sub1);
1320 drawBoxes(box->sub2); 1320 drawBoxes(box->sub2);
1321 } 1321 }
1322 else 1322 else
1323 drawBox(box); 1323 drawBox(box);
1324} 1324}
1325 1325
1326void calcBoxes(box *box) 1326void calcBoxes(box *box)
1327{ 1327{
1328 if (box->sub1) // If there's one sub box, there's always two. 1328 if (box->sub1) // If there's one sub box, there's always two.
1329 { 1329 {
1330 box->sub1->X = box->X; 1330 box->sub1->X = box->X;
1331 box->sub1->Y = box->Y; 1331 box->sub1->Y = box->Y;
1332 box->sub1->W = box->W; 1332 box->sub1->W = box->W;
1333 box->sub1->H = box->H; 1333 box->sub1->H = box->H;
1334 box->sub2->X = box->X; 1334 box->sub2->X = box->X;
1335 box->sub2->Y = box->Y; 1335 box->sub2->Y = box->Y;
1336 box->sub2->W = box->W; 1336 box->sub2->W = box->W;
1337 box->sub2->H = box->H; 1337 box->sub2->H = box->H;
1338 if (box->flags & BOX_HSPLIT) 1338 if (box->flags & BOX_HSPLIT)
1339 { 1339 {
1340 box->sub1->H *= box->split; 1340 box->sub1->H *= box->split;
1341 box->sub2->H -= box->sub1->H; 1341 box->sub2->H -= box->sub1->H;
1342 box->sub2->Y += box->sub1->H; 1342 box->sub2->Y += box->sub1->H;
1343 } 1343 }
1344 else 1344 else
1345 { 1345 {
1346 box->sub1->W *= box->split; 1346 box->sub1->W *= box->split;
1347 box->sub2->W -= box->sub1->W; 1347 box->sub2->W -= box->sub1->W;
1348 box->sub2->X += box->sub1->W; 1348 box->sub2->X += box->sub1->W;
1349 } 1349 }
1350 sizeViewToBox(box->sub1, -1, -1, -1, -1); 1350 sizeViewToBox(box->sub1, -1, -1, -1, -1);
1351 calcBoxes(box->sub1); 1351 calcBoxes(box->sub1);
1352 sizeViewToBox(box->sub2, -1, -1, -1, -1); 1352 sizeViewToBox(box->sub2, -1, -1, -1, -1);
1353 calcBoxes(box->sub2); 1353 calcBoxes(box->sub2);
1354 } 1354 }
1355 // Move the cursor to where it is, to check it's not now outside the box. 1355 // Move the cursor to where it is, to check it's not now outside the box.
1356 moveCursorAbsolute(box->view, box->view->cX, box->view->cY, 0, 0); 1356 moveCursorAbsolute(box->view, box->view->cX, box->view->cY, 0, 0);
1357 1357
1358 // We could call drawBoxes() here, but this is recursive, and so is drawBoxes(). 1358 // We could call drawBoxes() here, but this is recursive, and so is drawBoxes().
1359 // The combination might be deadly. Drawing the content of a box might be an expensive operation. 1359 // The combination might be deadly. Drawing the content of a box might be an expensive operation.
1360 // Later we might use a dirty box flag to deal with this, if it's not too much of a complication. 1360 // Later we might use a dirty box flag to deal with this, if it's not too much of a complication.
1361} 1361}
1362 1362
1363void deleteBox(view *view, event *event) 1363void deleteBox(view *view, event *event)
1364{ 1364{
1365 box *box = view->box; 1365 box *box = view->box;
1366 1366
1367 if (box->parent) 1367 if (box->parent)
1368 { 1368 {
1369 struct _box *oldBox = box, *otherBox = box->parent->sub1; 1369 struct _box *oldBox = box, *otherBox = box->parent->sub1;
1370 1370
1371 if (otherBox == oldBox) 1371 if (otherBox == oldBox)
1372 otherBox = box->parent->sub2; 1372 otherBox = box->parent->sub2;
1373 if (currentBox->parent == box->parent) 1373 if (currentBox->parent == box->parent)
1374 currentBox = box->parent; 1374 currentBox = box->parent;
1375 box = box->parent; 1375 box = box->parent;
1376 box->X = box->sub1->X; 1376 box->X = box->sub1->X;
1377 box->Y = box->sub1->Y; 1377 box->Y = box->sub1->Y;
1378 if (box->flags & BOX_HSPLIT) 1378 if (box->flags & BOX_HSPLIT)
1379 box->H = box->sub1->H + box->sub2->H; 1379 box->H = box->sub1->H + box->sub2->H;
1380 else 1380 else
1381 box->W = box->sub1->W + box->sub2->W; 1381 box->W = box->sub1->W + box->sub2->W;
1382 box->flags &= ~BOX_HSPLIT; 1382 box->flags &= ~BOX_HSPLIT;
1383 // Move the other sub boxes contents up to this box. 1383 // Move the other sub boxes contents up to this box.
1384 box->sub1 = otherBox->sub1; 1384 box->sub1 = otherBox->sub1;
1385 box->sub2 = otherBox->sub2; 1385 box->sub2 = otherBox->sub2;
1386 if (box->sub1) 1386 if (box->sub1)
1387 { 1387 {
1388 box->sub1->parent = box; 1388 box->sub1->parent = box;
1389 box->sub2->parent = box; 1389 box->sub2->parent = box;
1390 box->flags = otherBox->flags; 1390 box->flags = otherBox->flags;
1391 if (currentBox == box) 1391 if (currentBox == box)
1392 currentBox = box->sub1; 1392 currentBox = box->sub1;
1393 } 1393 }
1394 else 1394 else
1395 { 1395 {
1396 if (!box->parent) 1396 if (!box->parent)
1397 box->flags &= ~BOX_BORDER; 1397 box->flags &= ~BOX_BORDER;
1398 box->split = 1.0; 1398 box->split = 1.0;
1399 } 1399 }
1400 otherBox->sub1 = NULL; 1400 otherBox->sub1 = NULL;
1401 otherBox->sub2 = NULL; 1401 otherBox->sub2 = NULL;
1402 // Safe to free the boxes now that we have all their contents. 1402 // Safe to free the boxes now that we have all their contents.
1403 freeBox(otherBox); 1403 freeBox(otherBox);
1404 freeBox(oldBox); 1404 freeBox(oldBox);
1405 } 1405 }
1406 // Otherwise it must be a single full screen box. Never delete that one, unless we are quitting. 1406 // Otherwise it must be a single full screen box. Never delete that one, unless we are quitting.
1407 1407
1408 // Start the recursive recalculation of all the sub boxes. 1408 // Start the recursive recalculation of all the sub boxes.
1409 calcBoxes(box); 1409 calcBoxes(box);
1410 drawBoxes(box); 1410 drawBoxes(box);
1411} 1411}
1412 1412
1413void cloneBox(struct _box *box, struct _box *sub) 1413void cloneBox(struct _box *box, struct _box *sub)
1414{ 1414{
1415 sub->parent = box; 1415 sub->parent = box;
1416 // Only a full screen box has no border. 1416 // Only a full screen box has no border.
1417 sub->flags |= BOX_BORDER; 1417 sub->flags |= BOX_BORDER;
1418 sub->view = xmalloc(sizeof(struct _view)); 1418 sub->view = xmalloc(sizeof(struct _view));
1419 // TODO - After this is more stable, should check if the memcpy() is simpler than - xzalloc() then copy a few things manually. 1419 // TODO - After this is more stable, should check if the memcpy() is simpler than - xzalloc() then copy a few things manually.
1420 // Might even be able to arrange the structure so we can memcpy just part of it, leaving the rest blank. 1420 // Might even be able to arrange the structure so we can memcpy just part of it, leaving the rest blank.
1421 memcpy(sub->view, box->view, sizeof(struct _view)); 1421 memcpy(sub->view, box->view, sizeof(struct _view));
1422 sub->view->damage = NULL; 1422 sub->view->damage = NULL;
1423 sub->view->data = NULL; 1423 sub->view->data = NULL;
1424 sub->view->output = NULL; 1424 sub->view->output = NULL;
1425 sub->view->box = sub; 1425 sub->view->box = sub;
1426 if (box->view->prompt) 1426 if (box->view->prompt)
1427 sub->view->prompt = strdup(box->view->prompt); 1427 sub->view->prompt = strdup(box->view->prompt);
1428} 1428}
1429 1429
1430void splitBox(box *box, float split) 1430void splitBox(box *box, float split)
1431{ 1431{
1432 uint16_t size; 1432 uint16_t size;
1433 int otherBox = 0; 1433 int otherBox = 0;
1434 1434
1435 // First some sanity checks. 1435 // First some sanity checks.
1436 if (0.0 > split) 1436 if (0.0 > split)
1437 { 1437 {
1438 // TODO - put this in the status line, or just silently fail. Also, better message. lol 1438 // TODO - put this in the status line, or just silently fail. Also, better message. lol
1439 fprintf(stderr, "User is crazy.\n"); 1439 fprintf(stderr, "User is crazy.\n");
1440 return; 1440 return;
1441 } 1441 }
1442 else if (1.0 <= split) // User meant to unsplit, and it may already be split. 1442 else if (1.0 <= split) // User meant to unsplit, and it may already be split.
1443 { 1443 {
1444 // Actually, this means that the OTHER sub box gets deleted. 1444 // Actually, this means that the OTHER sub box gets deleted.
1445 if (box->parent) 1445 if (box->parent)
1446 { 1446 {
1447 if (box == box->parent->sub1) 1447 if (box == box->parent->sub1)
1448 deleteBox(box->parent->sub2->view, NULL); 1448 deleteBox(box->parent->sub2->view, NULL);
1449 else 1449 else
1450 deleteBox(box->parent->sub1->view, NULL); 1450 deleteBox(box->parent->sub1->view, NULL);
1451 } 1451 }
1452 return; 1452 return;
1453 } 1453 }
1454 else if (0.0 < split) // This is the normal case, so do nothing. 1454 else if (0.0 < split) // This is the normal case, so do nothing.
1455 { 1455 {
1456 } 1456 }
1457 else // User meant to delete this, zero split. 1457 else // User meant to delete this, zero split.
1458 { 1458 {
1459 deleteBox(box->view, NULL); 1459 deleteBox(box->view, NULL);
1460 return; 1460 return;
1461 } 1461 }
1462 if (box->flags & BOX_HSPLIT) 1462 if (box->flags & BOX_HSPLIT)
1463 size = box->H; 1463 size = box->H;
1464 else 1464 else
1465 size = box->W; 1465 size = box->W;
1466 if (6 > size) // Is there room for 2 borders for each sub box and one character of content each? 1466 if (6 > size) // Is there room for 2 borders for each sub box and one character of content each?
1467 // TODO - also should check the contents minimum size. 1467 // TODO - also should check the contents minimum size.
1468 // No need to check the no border case, that's only for full screen. 1468 // No need to check the no border case, that's only for full screen.
1469 // People using terminals smaller than 6 characters get what they deserve. 1469 // People using terminals smaller than 6 characters get what they deserve.
1470 { 1470 {
1471 // TODO - put this in the status line, or just silently fail. 1471 // TODO - put this in the status line, or just silently fail.
1472 fprintf(stderr, "Box is too small to split.\n"); 1472 fprintf(stderr, "Box is too small to split.\n");
1473 return; 1473 return;
1474 } 1474 }
1475 1475
1476 // Note that a split box is actually three boxes. The parent, which is not drawn, and the two subs, which are. 1476 // Note that a split box is actually three boxes. The parent, which is not drawn, and the two subs, which are.
1477 // Based on the assumption that there wont be lots of boxes, this keeps things simple. 1477 // Based on the assumption that there wont be lots of boxes, this keeps things simple.
1478 // It's possible that the box has already been split, and this is called just to update the split. 1478 // It's possible that the box has already been split, and this is called just to update the split.
1479 box->split = split; 1479 box->split = split;
1480 if (NULL == box->sub1) // If not split already, do so. 1480 if (NULL == box->sub1) // If not split already, do so.
1481 { 1481 {
1482 box->sub1 = xzalloc(sizeof(struct _box)); 1482 box->sub1 = xzalloc(sizeof(struct _box));
1483 box->sub2 = xzalloc(sizeof(struct _box)); 1483 box->sub2 = xzalloc(sizeof(struct _box));
1484 cloneBox(box, box->sub1); 1484 cloneBox(box, box->sub1);
1485 cloneBox(box, box->sub2); 1485 cloneBox(box, box->sub2);
1486 if (box->flags & BOX_HSPLIT) 1486 if (box->flags & BOX_HSPLIT)
1487 { 1487 {
1488 // Split the boxes in the middle of the content. 1488 // Split the boxes in the middle of the content.
1489 box->sub2->view->offsetY += (box->H * box->split) - 2; 1489 box->sub2->view->offsetY += (box->H * box->split) - 2;
1490 // Figure out which sub box the cursor will be in, then update the cursor in the other box. 1490 // Figure out which sub box the cursor will be in, then update the cursor in the other box.
1491 if (box->sub1->view->cY < box->sub2->view->offsetY) 1491 if (box->sub1->view->cY < box->sub2->view->offsetY)
1492 box->sub2->view->cY = box->sub2->view->offsetY; 1492 box->sub2->view->cY = box->sub2->view->offsetY;
1493 else 1493 else
1494 { 1494 {
1495 box->sub1->view->cY = box->sub2->view->offsetY - 1; 1495 box->sub1->view->cY = box->sub2->view->offsetY - 1;
1496 otherBox = 1; 1496 otherBox = 1;
1497 } 1497 }
1498 } 1498 }
1499 else 1499 else
1500 { 1500 {
1501 // Split the boxes in the middle of the content. 1501 // Split the boxes in the middle of the content.
1502 box->sub2->view->offsetX += (box->W * box->split) - 2; 1502 box->sub2->view->offsetX += (box->W * box->split) - 2;
1503 // Figure out which sub box the cursor will be in, then update the cursor in the other box. 1503 // Figure out which sub box the cursor will be in, then update the cursor in the other box.
1504 if (box->sub1->view->cX < box->sub2->view->offsetX) 1504 if (box->sub1->view->cX < box->sub2->view->offsetX)
1505 box->sub2->view->cX = box->sub2->view->offsetX; 1505 box->sub2->view->cX = box->sub2->view->offsetX;
1506 else 1506 else
1507 { 1507 {
1508 box->sub1->view->cX = box->sub2->view->offsetX - 1; 1508 box->sub1->view->cX = box->sub2->view->offsetX - 1;
1509 otherBox = 1; 1509 otherBox = 1;
1510 } 1510 }
1511 } 1511 }
1512 } 1512 }
1513 1513
1514 if ((currentBox == box) && (box->sub1)) 1514 if ((currentBox == box) && (box->sub1))
1515 { 1515 {
1516 if (otherBox) 1516 if (otherBox)
1517 currentBox = box->sub2; 1517 currentBox = box->sub2;
1518 else 1518 else
1519 currentBox = box->sub1; 1519 currentBox = box->sub1;
1520 } 1520 }
1521 1521
1522 // Start the recursive recalculation of all the sub boxes. 1522 // Start the recursive recalculation of all the sub boxes.
1523 calcBoxes(box); 1523 calcBoxes(box);
1524 drawBoxes(box); 1524 drawBoxes(box);
1525} 1525}
1526 1526
1527// TODO - Might be better to just have a double linked list of boxes, and traverse that instead. 1527// TODO - Might be better to just have a double linked list of boxes, and traverse that instead.
1528// Except that leaves a problem when deleting boxes, could end up with a blank space. 1528// Except that leaves a problem when deleting boxes, could end up with a blank space.
1529void switchBoxes(view *view, event *event) 1529void switchBoxes(view *view, event *event)
1530{ 1530{
1531 box *box = view->box; 1531 box *box = view->box;
1532 1532
1533 // The assumption here is that box == currentBox. 1533 // The assumption here is that box == currentBox.
1534 struct _box *oldBox = currentBox; 1534 struct _box *oldBox = currentBox;
1535 struct _box *thisBox = box; 1535 struct _box *thisBox = box;
1536 int backingUp = 0; 1536 int backingUp = 0;
1537 1537
1538 // Depth first traversal. 1538 // Depth first traversal.
1539 while ((oldBox == currentBox) && (thisBox->parent)) 1539 while ((oldBox == currentBox) && (thisBox->parent))
1540 { 1540 {
1541 if (thisBox == thisBox->parent->sub1) 1541 if (thisBox == thisBox->parent->sub1)
1542 { 1542 {
1543 if (backingUp && (thisBox->parent)) 1543 if (backingUp && (thisBox->parent))
1544 currentBox = thisBox->parent->sub2; 1544 currentBox = thisBox->parent->sub2;
1545 else if (thisBox->sub1) 1545 else if (thisBox->sub1)
1546 currentBox = thisBox->sub1; 1546 currentBox = thisBox->sub1;
1547 else 1547 else
1548 currentBox = thisBox->parent->sub2; 1548 currentBox = thisBox->parent->sub2;
1549 } 1549 }
1550 else if (thisBox == thisBox->parent->sub2) 1550 else if (thisBox == thisBox->parent->sub2)
1551 { 1551 {
1552 thisBox = thisBox->parent; 1552 thisBox = thisBox->parent;
1553 backingUp = 1; 1553 backingUp = 1;
1554 } 1554 }
1555 } 1555 }
1556 1556
1557 // If we have not found the next box to move to, move back to the beginning. 1557 // If we have not found the next box to move to, move back to the beginning.
1558 if (oldBox == currentBox) 1558 if (oldBox == currentBox)
1559 currentBox = rootBox; 1559 currentBox = rootBox;
1560 1560
1561 // If we ended up on a parent box, go to it's first sub. 1561 // If we ended up on a parent box, go to it's first sub.
1562 while (currentBox->sub1) 1562 while (currentBox->sub1)
1563 currentBox = currentBox->sub1; 1563 currentBox = currentBox->sub1;
1564 1564
1565 // Just redraw them all. 1565 // Just redraw them all.
1566 drawBoxes(rootBox); 1566 drawBoxes(rootBox);
1567} 1567}
1568 1568
1569// TODO - It might be better to do away with this bunch of single line functions 1569// TODO - It might be better to do away with this bunch of single line functions
@@ -1573,157 +1573,157 @@ void switchBoxes(view *view, event *event)
1573 1573
1574void halveBoxHorizontally(view *view, event *event) 1574void halveBoxHorizontally(view *view, event *event)
1575{ 1575{
1576 view->box->flags |= BOX_HSPLIT; 1576 view->box->flags |= BOX_HSPLIT;
1577 splitBox(view->box, 0.5); 1577 splitBox(view->box, 0.5);
1578} 1578}
1579 1579
1580void halveBoxVertically(view *view, event *event) 1580void halveBoxVertically(view *view, event *event)
1581{ 1581{
1582 view->box->flags &= ~BOX_HSPLIT; 1582 view->box->flags &= ~BOX_HSPLIT;
1583 splitBox(view->box, 0.5); 1583 splitBox(view->box, 0.5);
1584} 1584}
1585 1585
1586void switchMode(view *view, event *event) 1586void switchMode(view *view, event *event)
1587{ 1587{
1588 currentBox->view->mode++; 1588 currentBox->view->mode++;
1589 // Assumes that modes will always have a key mapping, which I think is a safe bet. 1589 // Assumes that modes will always have a key mapping, which I think is a safe bet.
1590 if (NULL == currentBox->view->content->context->modes[currentBox->view->mode].keys) 1590 if (NULL == currentBox->view->content->context->modes[currentBox->view->mode].keys)
1591 currentBox->view->mode = 0; 1591 currentBox->view->mode = 0;
1592 commandMode = currentBox->view->content->context->modes[currentBox->view->mode].flags & 1; 1592 commandMode = currentBox->view->content->context->modes[currentBox->view->mode].flags & 1;
1593} 1593}
1594 1594
1595void leftChar(view *view, event *event) 1595void leftChar(view *view, event *event)
1596{ 1596{
1597 moveCursorRelative(view, -1, 0, 0, 0); 1597 moveCursorRelative(view, -1, 0, 0, 0);
1598} 1598}
1599 1599
1600void rightChar(view *view, event *event) 1600void rightChar(view *view, event *event)
1601{ 1601{
1602 moveCursorRelative(view, 1, 0, 0, 0); 1602 moveCursorRelative(view, 1, 0, 0, 0);
1603} 1603}
1604 1604
1605void upLine(view *view, event *event) 1605void upLine(view *view, event *event)
1606{ 1606{
1607 moveCursorRelative(view, 0, -1, 0, 0); 1607 moveCursorRelative(view, 0, -1, 0, 0);
1608} 1608}
1609 1609
1610void downLine(view *view, event *event) 1610void downLine(view *view, event *event)
1611{ 1611{
1612 moveCursorRelative(view, 0, 1, 0, 0); 1612 moveCursorRelative(view, 0, 1, 0, 0);
1613} 1613}
1614 1614
1615void upPage(view *view, event *event) 1615void upPage(view *view, event *event)
1616{ 1616{
1617 moveCursorRelative(view, 0, 0 - (view->H - 1), 0, 0 - (view->H - 1)); 1617 moveCursorRelative(view, 0, 0 - (view->H - 1), 0, 0 - (view->H - 1));
1618} 1618}
1619 1619
1620void downPage(view *view, event *event) 1620void downPage(view *view, event *event)
1621{ 1621{
1622 moveCursorRelative(view, 0, view->H - 1, 0, view->H - 1); 1622 moveCursorRelative(view, 0, view->H - 1, 0, view->H - 1);
1623} 1623}
1624 1624
1625void endOfLine(view *view, event *event) 1625void endOfLine(view *view, event *event)
1626{ 1626{
1627 moveCursorAbsolute(view, strlen(view->prompt) + view->oW, view->cY, 0, 0); 1627 moveCursorAbsolute(view, strlen(view->prompt) + view->oW, view->cY, 0, 0);
1628} 1628}
1629 1629
1630void startOfLine(view *view, event *event) 1630void startOfLine(view *view, event *event)
1631{ 1631{
1632 // TODO - add the advanced editing "smart home". 1632 // TODO - add the advanced editing "smart home".
1633 moveCursorAbsolute(view, strlen(view->prompt), view->cY, 0, 0); 1633 moveCursorAbsolute(view, strlen(view->prompt), view->cY, 0, 0);
1634} 1634}
1635 1635
1636void splitLine(view *view, event *event) 1636void splitLine(view *view, event *event)
1637{ 1637{
1638 // TODO - should move this into mooshLines(). 1638 // TODO - should move this into mooshLines().
1639 addLine(view->content, view->line, &(view->line->line[view->iX]), 0); 1639 addLine(view->content, view->line, &(view->line->line[view->iX]), 0);
1640 view->line->line[view->iX] = '\0'; 1640 view->line->line[view->iX] = '\0';
1641 moveCursorAbsolute(view, 0, view->cY + 1, 0, 0); 1641 moveCursorAbsolute(view, 0, view->cY + 1, 0, 0);
1642 if (view->box) 1642 if (view->box)
1643 drawBox(view->box); 1643 drawBox(view->box);
1644} 1644}
1645 1645
1646void deleteChar(view *view, event *event) 1646void deleteChar(view *view, event *event)
1647{ 1647{
1648 // TODO - should move this into mooshLines(). 1648 // TODO - should move this into mooshLines().
1649 // If we are at the end of the line, then join this and the next line. 1649 // If we are at the end of the line, then join this and the next line.
1650 if (view->oW == view->cX) 1650 if (view->oW == view->cX)
1651 { 1651 {
1652 // Only if there IS a next line. 1652 // Only if there IS a next line.
1653 if (&(view->content->lines) != view->line->next) 1653 if (&(view->content->lines) != view->line->next)
1654 { 1654 {
1655 mooshStrings(view->line, view->line->next->line, view->iX, 1, !TT.overWriteMode); 1655 mooshStrings(view->line, view->line->next->line, view->iX, 1, !TT.overWriteMode);
1656 view->line->next->line = NULL; 1656 view->line->next->line = NULL;
1657 freeLine(view->content, view->line->next); 1657 freeLine(view->content, view->line->next);
1658 // TODO - should check if we are on the last page, then deal with scrolling. 1658 // TODO - should check if we are on the last page, then deal with scrolling.
1659 if (view->box) 1659 if (view->box)
1660 drawBox(view->box); 1660 drawBox(view->box);
1661 } 1661 }
1662 } 1662 }
1663 else 1663 else
1664 mooshStrings(view->line, NULL, view->iX, 1, !TT.overWriteMode); 1664 mooshStrings(view->line, NULL, view->iX, 1, !TT.overWriteMode);
1665} 1665}
1666 1666
1667void backSpaceChar(view *view, event *event) 1667void backSpaceChar(view *view, event *event)
1668{ 1668{
1669 if (moveCursorRelative(view, -1, 0, 0, 0)) 1669 if (moveCursorRelative(view, -1, 0, 0, 0))
1670 deleteChar(view, event); 1670 deleteChar(view, event);
1671} 1671}
1672 1672
1673void saveContent(view *view, event *event) 1673void saveContent(view *view, event *event)
1674{ 1674{
1675 saveFile(view->content); 1675 saveFile(view->content);
1676} 1676}
1677 1677
1678void executeLine(view *view, event *event) 1678void executeLine(view *view, event *event)
1679{ 1679{
1680 struct line *result = view->line; 1680 struct line *result = view->line;
1681 1681
1682 // Don't bother doing much if there's nothing on this line. 1682 // Don't bother doing much if there's nothing on this line.
1683 if (result->line[0]) 1683 if (result->line[0])
1684 { 1684 {
1685 doCommand(currentBox->view->content->context->commands, result->line, currentBox->view, event); 1685 doCommand(currentBox->view->content->context->commands, result->line, currentBox->view, event);
1686 // If we are not at the end of the history contents. 1686 // If we are not at the end of the history contents.
1687 if (&(view->content->lines) != result->next) 1687 if (&(view->content->lines) != result->next)
1688 { 1688 {
1689 struct line *line = view->content->lines.prev; 1689 struct line *line = view->content->lines.prev;
1690 1690
1691 // Remove the line first. 1691 // Remove the line first.
1692 result->next->prev = result->prev; 1692 result->next->prev = result->prev;
1693 result->prev->next = result->next; 1693 result->prev->next = result->next;
1694 // Check if the last line is already blank, then remove it. 1694 // Check if the last line is already blank, then remove it.
1695 if ('\0' == line->line[0]) 1695 if ('\0' == line->line[0])
1696 { 1696 {
1697 freeLine(view->content, line); 1697 freeLine(view->content, line);
1698 line = view->content->lines.prev; 1698 line = view->content->lines.prev;
1699 } 1699 }
1700 // Then add it to the end. 1700 // Then add it to the end.
1701 result->next = line->next; 1701 result->next = line->next;
1702 result->prev = line; 1702 result->prev = line;
1703 line->next->prev = result; 1703 line->next->prev = result;
1704 line->next = result; 1704 line->next = result;
1705 view->cY = view->content->lines.length - 1; 1705 view->cY = view->content->lines.length - 1;
1706 } 1706 }
1707 moveCursorAbsolute(view, 0, view->content->lines.length, 0, 0); 1707 moveCursorAbsolute(view, 0, view->content->lines.length, 0, 0);
1708 // Make sure there is one blank line at the end. 1708 // Make sure there is one blank line at the end.
1709 if ('\0' != view->line->line[0]) 1709 if ('\0' != view->line->line[0])
1710 { 1710 {
1711 endOfLine(view, event); 1711 endOfLine(view, event);
1712 splitLine(view, event); 1712 splitLine(view, event);
1713 } 1713 }
1714 } 1714 }
1715 1715
1716 saveFile(view->content); 1716 saveFile(view->content);
1717} 1717}
1718 1718
1719void quit(view *view, event *event) 1719void quit(view *view, event *event)
1720{ 1720{
1721 TT.stillRunning = 0; 1721 TT.stillRunning = 0;
1722} 1722}
1723 1723
1724void nop(box *box, event *event) 1724void nop(box *box, event *event)
1725{ 1725{
1726 // 'tis a nop, don't actually do anything. 1726 // 'tis a nop, don't actually do anything.
1727} 1727}
1728 1728
1729 1729
@@ -1738,188 +1738,188 @@ void nop(box *box, event *event)
1738// X, Y, W, and H can be -1, which means to grab suitable numbers from the views box. 1738// X, Y, W, and H can be -1, which means to grab suitable numbers from the views box.
1739void editLine(view *view, int16_t X, int16_t Y, int16_t W, int16_t H) 1739void editLine(view *view, int16_t X, int16_t Y, int16_t W, int16_t H)
1740{ 1740{
1741 struct termios termio, oldtermio; 1741 struct termios termio, oldtermio;
1742 struct pollfd pollfds[1]; 1742 struct pollfd pollfds[1];
1743 char buffer[BUFFER_LEN + 1]; 1743 char buffer[BUFFER_LEN + 1];
1744 char command[BUFFER_LEN + 1]; 1744 char command[BUFFER_LEN + 1];
1745 int pollcount = 1; 1745 int pollcount = 1;
1746 int i = 0; 1746 int i = 0;
1747// TODO - multiline editLine is an advanced feature. Editing boxes just moves the editLine up and down. 1747// TODO - multiline editLine is an advanced feature. Editing boxes just moves the editLine up and down.
1748// uint16_t h = 1; 1748// uint16_t h = 1;
1749// TODO - should check if it's at the top of the box, then grow it down instead of up if so. 1749// TODO - should check if it's at the top of the box, then grow it down instead of up if so.
1750 1750
1751 buffer[0] = 0; 1751 buffer[0] = 0;
1752 command[0] = 0; 1752 command[0] = 0;
1753 1753
1754 if (view->box) 1754 if (view->box)
1755 sizeViewToBox(view->box, X, Y, W, H); 1755 sizeViewToBox(view->box, X, Y, W, H);
1756 // Assumes the view was already setup if it's not part of a box. 1756 // Assumes the view was already setup if it's not part of a box.
1757 1757
1758 // All the mouse tracking methods suck one way or another. sigh 1758 // All the mouse tracking methods suck one way or another. sigh
1759 // Enable mouse (VT200 normal tracking mode, UTF8 encoding). The limit is 2015. Seems to only be in later xterms. 1759 // Enable mouse (VT200 normal tracking mode, UTF8 encoding). The limit is 2015. Seems to only be in later xterms.
1760// printf("\x1B[?1005h"); 1760// printf("\x1B[?1005h");
1761 // Enable mouse (DEC locator reporting mode). In theory has no limit. Wont actually work though. 1761 // Enable mouse (DEC locator reporting mode). In theory has no limit. Wont actually work though.
1762 // On the other hand, only allows for four buttons, so only half a mouse wheel. 1762 // On the other hand, only allows for four buttons, so only half a mouse wheel.
1763// printf("\x1B[1;2'z\x1B[1;3'{"); 1763// printf("\x1B[1;2'z\x1B[1;3'{");
1764 // Enable mouse (VT200 normal tracking mode). Has a limit of 256 - 32 rows and columns. An xterm exclusive I think, but works in roxterm at least. 1764 // Enable mouse (VT200 normal tracking mode). Has a limit of 256 - 32 rows and columns. An xterm exclusive I think, but works in roxterm at least.
1765 printf("\x1B[?1000h"); 1765 printf("\x1B[?1000h");
1766 fflush(stdout); 1766 fflush(stdout);
1767 // TODO - Should remember to turn off mouse reporting when we leave. 1767 // TODO - Should remember to turn off mouse reporting when we leave.
1768 1768
1769 // Grab the old terminal settings and save it. 1769 // Grab the old terminal settings and save it.
1770 tcgetattr(0, &oldtermio); 1770 tcgetattr(0, &oldtermio);
1771 tcflush(0, TCIFLUSH); 1771 tcflush(0, TCIFLUSH);
1772 termio = oldtermio; 1772 termio = oldtermio;
1773 1773
1774 // Mould the terminal to our will. 1774 // Mould the terminal to our will.
1775 termio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); 1775 termio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
1776 termio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP|ICANON); 1776 termio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP|ICANON);
1777 termio.c_cc[VTIME]=0; // deciseconds. 1777 termio.c_cc[VTIME]=0; // deciseconds.
1778 termio.c_cc[VMIN]=1; 1778 termio.c_cc[VMIN]=1;
1779 tcsetattr(0, TCSANOW, &termio); 1779 tcsetattr(0, TCSANOW, &termio);
1780 1780
1781 calcBoxes(currentBox); 1781 calcBoxes(currentBox);
1782 drawBoxes(currentBox); 1782 drawBoxes(currentBox);
1783 1783
1784 // TODO - OS buffered keys might be a problem, but we can't do the usual timestamp filter for now. 1784 // TODO - OS buffered keys might be a problem, but we can't do the usual timestamp filter for now.
1785 while (TT.stillRunning) 1785 while (TT.stillRunning)
1786 { 1786 {
1787 // TODO - We can reuse one or two of these to have less of them. 1787 // TODO - We can reuse one or two of these to have less of them.
1788 int j = 0, p, ret, y, len; 1788 int j = 0, p, ret, y, len;
1789 1789
1790 // Coz things might change out from under us, find the current view. 1790 // Coz things might change out from under us, find the current view.
1791 // TODO - see if I can get this lot out of here. 1791 // TODO - see if I can get this lot out of here.
1792 if (commandMode) 1792 if (commandMode)
1793 view = commandLine; 1793 view = commandLine;
1794 else 1794 else
1795 view = currentBox->view; 1795 view = currentBox->view;
1796 y = view->Y + (view->cY - view->offsetY); 1796 y = view->Y + (view->cY - view->offsetY);
1797 len = strlen(view->prompt); 1797 len = strlen(view->prompt);
1798 drawLine(y, view->X, view->X + view->W, "\0", " ", view->prompt, '\0', 0); 1798 drawLine(y, view->X, view->X + view->W, "\0", " ", view->prompt, '\0', 0);
1799 drawContentLine(view, y, view->X + len, view->X + view->W, "\0", " ", view->line->line, '\0', 1); 1799 drawContentLine(view, y, view->X + len, view->X + view->W, "\0", " ", view->line->line, '\0', 1);
1800 printf("\x1B[%d;%dH", y + 1, view->X + len + (view->cX - view->offsetX) + 1); 1800 printf("\x1B[%d;%dH", y + 1, view->X + len + (view->cX - view->offsetX) + 1);
1801 fflush(stdout); 1801 fflush(stdout);
1802 1802
1803 // Apparently it's more portable to reset this each time. 1803 // Apparently it's more portable to reset this each time.
1804 memset(pollfds, 0, pollcount * sizeof(struct pollfd)); 1804 memset(pollfds, 0, pollcount * sizeof(struct pollfd));
1805 pollfds[0].events = POLLIN; 1805 pollfds[0].events = POLLIN;
1806 pollfds[0].fd = 0; 1806 pollfds[0].fd = 0;
1807 1807
1808 // TODO - Should only ask for a time out after we get an Escape. 1808 // TODO - Should only ask for a time out after we get an Escape.
1809 p = poll(pollfds, pollcount, 100); // Timeout of one tenth of a second (100). 1809 p = poll(pollfds, pollcount, 100); // Timeout of one tenth of a second (100).
1810 if (0 > p) perror_exit("poll"); 1810 if (0 > p) perror_exit("poll");
1811 if (0 == p) // A timeout, trigger a time event. 1811 if (0 == p) // A timeout, trigger a time event.
1812 { 1812 {
1813 if ((1 == i) && ('\x1B' == buffer[0])) 1813 if ((1 == i) && ('\x1B' == buffer[0]))
1814 { 1814 {
1815 // After a short delay to check, this is a real Escape key, not part of an escape sequence, so deal with it. 1815 // After a short delay to check, this is a real Escape key, not part of an escape sequence, so deal with it.
1816 strcpy(command, "^["); 1816 strcpy(command, "^[");
1817 i = 0; 1817 i = 0;
1818 buffer[0] = 0; 1818 buffer[0] = 0;
1819 } 1819 }
1820 // TODO - Send a timer event somewhere. This wont be a precise timed event, but don't think we need one. 1820 // TODO - Send a timer event somewhere. This wont be a precise timed event, but don't think we need one.
1821 } 1821 }
1822 1822
1823 while (0 < p) 1823 while (0 < p)
1824 { 1824 {
1825 p--; 1825 p--;
1826 if (pollfds[p].revents & POLLIN) 1826 if (pollfds[p].revents & POLLIN)
1827 { 1827 {
1828 // I am assuming that we get the input atomically, each multibyte key fits neatly into one read. 1828 // I am assuming that we get the input atomically, each multibyte key fits neatly into one read.
1829 // If that's not true (which is entirely likely), then we have to get complicated with circular buffers and stuff, or just one byte at a time. 1829 // If that's not true (which is entirely likely), then we have to get complicated with circular buffers and stuff, or just one byte at a time.
1830 ret = read(pollfds[p].fd, &buffer[i], BUFFER_LEN - i); 1830 ret = read(pollfds[p].fd, &buffer[i], BUFFER_LEN - i);
1831 if (ret < 0) // An error happened. 1831 if (ret < 0) // An error happened.
1832 { 1832 {
1833 // For now, just ignore errors. 1833 // For now, just ignore errors.
1834 fprintf(stderr, "input error on %d\n", p); 1834 fprintf(stderr, "input error on %d\n", p);
1835 fflush(stderr); 1835 fflush(stderr);
1836 } 1836 }
1837 else if (ret == 0) // End of file. 1837 else if (ret == 0) // End of file.
1838 { 1838 {
1839 fprintf(stderr, "EOF\n"); 1839 fprintf(stderr, "EOF\n");
1840 fflush(stderr); 1840 fflush(stderr);
1841 } 1841 }
1842 else 1842 else
1843 { 1843 {
1844 i += ret; 1844 i += ret;
1845 if (BUFFER_LEN <= i) // Ran out of buffer. 1845 if (BUFFER_LEN <= i) // Ran out of buffer.
1846 { 1846 {
1847 fprintf(stderr, "Full buffer - %s -> %s\n", buffer, command); 1847 fprintf(stderr, "Full buffer - %s -> %s\n", buffer, command);
1848 for (j = 0; buffer[j + 1]; j++) 1848 for (j = 0; buffer[j + 1]; j++)
1849 fprintf(stderr, "(%x) %c, ", (int) buffer[j], buffer[j]); 1849 fprintf(stderr, "(%x) %c, ", (int) buffer[j], buffer[j]);
1850 fflush(stderr); 1850 fflush(stderr);
1851 i = 0; 1851 i = 0;
1852 buffer[0] = 0; 1852 buffer[0] = 0;
1853 } 1853 }
1854 else 1854 else
1855 buffer[i] = 0; 1855 buffer[i] = 0;
1856 } 1856 }
1857 } 1857 }
1858 } 1858 }
1859 1859
1860// TODO - think vi got screwed up now. sigh 1860// TODO - think vi got screwed up now. sigh
1861 1861
1862 // For a real timeout checked Esc, buffer is now empty, so this for loop wont find it anyway. 1862 // For a real timeout checked Esc, buffer is now empty, so this for loop wont find it anyway.
1863 // While it's true we could avoid it by checking, the user already had to wait for a time out, and this loop wont take THAT long. 1863 // While it's true we could avoid it by checking, the user already had to wait for a time out, and this loop wont take THAT long.
1864 for (j = 0; keys[j].code; j++) // Search for multibyte keys and some control keys. 1864 for (j = 0; keys[j].code; j++) // Search for multibyte keys and some control keys.
1865 { 1865 {
1866 if (strcmp(keys[j].code, buffer) == 0) 1866 if (strcmp(keys[j].code, buffer) == 0)
1867 { 1867 {
1868 strcat(command, keys[j].name); 1868 strcat(command, keys[j].name);
1869 i = 0; 1869 i = 0;
1870 buffer[0] = 0; 1870 buffer[0] = 0;
1871 break; 1871 break;
1872 } 1872 }
1873 } 1873 }
1874 1874
1875 // See if it's an ordinary key, 1875 // See if it's an ordinary key,
1876 if ((1 == i) && isprint(buffer[0])) 1876 if ((1 == i) && isprint(buffer[0]))
1877 { 1877 {
1878 // If there's an outstanding command, add this to the end of it. 1878 // If there's an outstanding command, add this to the end of it.
1879 if (command[0]) 1879 if (command[0])
1880 strcat(command, buffer); 1880 strcat(command, buffer);
1881 else 1881 else
1882 { 1882 {
1883 // TODO - Should check for tabs to, and insert them. 1883 // TODO - Should check for tabs to, and insert them.
1884 // Though better off having a function for that? 1884 // Though better off having a function for that?
1885 // TODO - see if I can get these out of here. Some sort of pushCharacter(buffer, blob) that is passed in. 1885 // TODO - see if I can get these out of here. Some sort of pushCharacter(buffer, blob) that is passed in.
1886 mooshStrings(view->line, buffer, view->iX, 0, !TT.overWriteMode); 1886 mooshStrings(view->line, buffer, view->iX, 0, !TT.overWriteMode);
1887 view->oW = formatLine(view, view->line->line, &(view->output)); 1887 view->oW = formatLine(view, view->line->line, &(view->output));
1888 moveCursorRelative(view, strlen(buffer), 0, 0, 0); 1888 moveCursorRelative(view, strlen(buffer), 0, 0, 0);
1889 } 1889 }
1890 i = 0; 1890 i = 0;
1891 buffer[0] = 0; 1891 buffer[0] = 0;
1892 } 1892 }
1893 1893
1894 // TODO - If the view->context has on event handler, use it, otherwise look up the specific event handler in the context modes ourselves. 1894 // TODO - If the view->context has on event handler, use it, otherwise look up the specific event handler in the context modes ourselves.
1895 if (command[0]) // Search for a bound key. 1895 if (command[0]) // Search for a bound key.
1896 { 1896 {
1897 if (BUFFER_LEN <= strlen(command)) 1897 if (BUFFER_LEN <= strlen(command))
1898 { 1898 {
1899 fprintf(stderr, "Full command buffer - %s \n", command); 1899 fprintf(stderr, "Full command buffer - %s \n", command);
1900 fflush(stderr); 1900 fflush(stderr);
1901 command[0] = 0; 1901 command[0] = 0;
1902 } 1902 }
1903 1903
1904 // This is using the currentBox instead of view, coz the command line keys are part of the box context now, not separate. 1904 // This is using the currentBox instead of view, coz the command line keys are part of the box context now, not separate.
1905 // More importantly, the currentBox may change due to a command. 1905 // More importantly, the currentBox may change due to a command.
1906 struct keyCommand *ourKeys = currentBox->view->content->context->modes[currentBox->view->mode].keys; 1906 struct keyCommand *ourKeys = currentBox->view->content->context->modes[currentBox->view->mode].keys;
1907 1907
1908 for (j = 0; ourKeys[j].key; j++) 1908 for (j = 0; ourKeys[j].key; j++)
1909 { 1909 {
1910 if (strcmp(ourKeys[j].key, command) == 0) 1910 if (strcmp(ourKeys[j].key, command) == 0)
1911 { 1911 {
1912 doCommand(view->content->context->commands, ourKeys[j].command, view, NULL); 1912 doCommand(view->content->context->commands, ourKeys[j].command, view, NULL);
1913 command[0] = 0; 1913 command[0] = 0;
1914 break; 1914 break;
1915 } 1915 }
1916 } 1916 }
1917 } 1917 }
1918 1918
1919 } 1919 }
1920 1920
1921 // Restore the old terminal settings. 1921 // Restore the old terminal settings.
1922 tcsetattr(0, TCSANOW, &oldtermio); 1922 tcsetattr(0, TCSANOW, &oldtermio);
1923} 1923}
1924 1924
1925 1925
@@ -1927,26 +1927,26 @@ void editLine(view *view, int16_t X, int16_t Y, int16_t W, int16_t H)
1927// Though most of the editors have their own variation. Maybe just use the joe one as default, it uses short names at least. 1927// Though most of the editors have their own variation. Maybe just use the joe one as default, it uses short names at least.
1928struct function simpleEditCommands[] = 1928struct function simpleEditCommands[] =
1929{ 1929{
1930 {"backSpaceChar","Back space last character.", 0, {backSpaceChar}}, 1930 {"backSpaceChar", "Back space last character.", 0, {backSpaceChar}},
1931 {"deleteBox", "Delete a box.", 0, {deleteBox}}, 1931 {"deleteBox", "Delete a box.", 0, {deleteBox}},
1932 {"deleteChar", "Delete current character.", 0, {deleteChar}}, 1932 {"deleteChar", "Delete current character.", 0, {deleteChar}},
1933 {"downLine", "Move cursor down one line.", 0, {downLine}}, 1933 {"downLine", "Move cursor down one line.", 0, {downLine}},
1934 {"downPage", "Move cursor down one page.", 0, {downPage}}, 1934 {"downPage", "Move cursor down one page.", 0, {downPage}},
1935 {"endOfLine", "Go to end of line.", 0, {endOfLine}}, 1935 {"endOfLine", "Go to end of line.", 0, {endOfLine}},
1936 {"executeLine", "Execute a line as a script.", 0, {executeLine}}, 1936 {"executeLine", "Execute a line as a script.", 0, {executeLine}},
1937 {"leftChar", "Move cursor left one character.", 0, {leftChar}}, 1937 {"leftChar", "Move cursor left one character.", 0, {leftChar}},
1938 {"quit", "Quit the application.", 0, {quit}}, 1938 {"quit", "Quit the application.", 0, {quit}},
1939 {"rightChar", "Move cursor right one character.", 0, {rightChar}}, 1939 {"rightChar", "Move cursor right one character.", 0, {rightChar}},
1940 {"save", "Save.", 0, {saveContent}}, 1940 {"save", "Save.", 0, {saveContent}},
1941 {"splitH", "Split box in half horizontally.", 0, {halveBoxHorizontally}}, 1941 {"splitH", "Split box in half horizontally.", 0, {halveBoxHorizontally}},
1942 {"splitLine", "Split line at cursor.", 0, {splitLine}}, 1942 {"splitLine", "Split line at cursor.", 0, {splitLine}},
1943 {"splitV", "Split box in half vertically.", 0, {halveBoxVertically}}, 1943 {"splitV", "Split box in half vertically.", 0, {halveBoxVertically}},
1944 {"startOfLine", "Go to start of line.", 0, {startOfLine}}, 1944 {"startOfLine", "Go to start of line.", 0, {startOfLine}},
1945 {"switchBoxes", "Switch to another box.", 0, {switchBoxes}}, 1945 {"switchBoxes", "Switch to another box.", 0, {switchBoxes}},
1946 {"switchMode", "Switch between command and box.", 0, {switchMode}}, 1946 {"switchMode", "Switch between command and box.", 0, {switchMode}},
1947 {"upLine", "Move cursor up one line.", 0, {upLine}}, 1947 {"upLine", "Move cursor up one line.", 0, {upLine}},
1948 {"upPage", "Move cursor up one page.", 0, {upPage}}, 1948 {"upPage", "Move cursor up one page.", 0, {upPage}},
1949 {NULL, NULL, 0, {NULL}} 1949 {NULL, NULL, 0, {NULL}}
1950}; 1950};
1951 1951
1952// Construct a simple command line. 1952// Construct a simple command line.
@@ -1955,18 +1955,18 @@ struct function simpleEditCommands[] =
1955// TODO - Should not move off the ends of the line to the next / previous line. 1955// TODO - Should not move off the ends of the line to the next / previous line.
1956struct keyCommand simpleCommandKeys[] = 1956struct keyCommand simpleCommandKeys[] =
1957{ 1957{
1958 {"BS", "backSpaceChar"}, 1958 {"BS", "backSpaceChar"},
1959 {"Del", "deleteChar"}, 1959 {"Del", "deleteChar"},
1960 {"Down", "downLine"}, 1960 {"Down", "downLine"},
1961 {"End", "endOfLine"}, 1961 {"End", "endOfLine"},
1962 {"F10", "quit"}, 1962 {"F10", "quit"},
1963 {"Home", "startOfLine"}, 1963 {"Home", "startOfLine"},
1964 {"Left", "leftChar"}, 1964 {"Left", "leftChar"},
1965 {"Return", "executeLine"}, 1965 {"Return", "executeLine"},
1966 {"Right", "rightChar"}, 1966 {"Right", "rightChar"},
1967 {"^[", "switchMode"}, 1967 {"^[", "switchMode"},
1968 {"Up", "upLine"}, 1968 {"Up", "upLine"},
1969 {NULL, NULL} 1969 {NULL, NULL}
1970}; 1970};
1971 1971
1972 1972
@@ -1981,98 +1981,98 @@ struct keyCommand simpleCommandKeys[] =
1981// readline uses these same commands, and defaults to emacs keystrokes. 1981// readline uses these same commands, and defaults to emacs keystrokes.
1982struct function simpleEmacsCommands[] = 1982struct function simpleEmacsCommands[] =
1983{ 1983{
1984 {"delete-backward-char", "Back space last character.", 0, {backSpaceChar}}, 1984 {"delete-backward-char", "Back space last character.", 0, {backSpaceChar}},
1985 {"delete-window", "Delete a box.", 0, {deleteBox}}, 1985 {"delete-window", "Delete a box.", 0, {deleteBox}},
1986 {"delete-char", "Delete current character.", 0, {deleteChar}}, 1986 {"delete-char", "Delete current character.", 0, {deleteChar}},
1987 {"next-line", "Move cursor down one line.", 0, {downLine}}, 1987 {"next-line", "Move cursor down one line.", 0, {downLine}},
1988 {"scroll-up", "Move cursor down one page.", 0, {downPage}}, 1988 {"scroll-up", "Move cursor down one page.", 0, {downPage}},
1989 {"end-of-line", "Go to end of line.", 0, {endOfLine}}, 1989 {"end-of-line", "Go to end of line.", 0, {endOfLine}},
1990 {"accept-line", "Execute a line as a script.", 0, {executeLine}}, // From readline, which uses emacs commands, coz mg at least does not seem to have this. 1990 {"accept-line", "Execute a line as a script.", 0, {executeLine}}, // From readline, which uses emacs commands, coz mg at least does not seem to have this.
1991 {"backward-char", "Move cursor left one character.", 0, {leftChar}}, 1991 {"backward-char", "Move cursor left one character.", 0, {leftChar}},
1992 {"save-buffers-kill-emacs", "Quit the application.", 0, {quit}}, // Does more than just quit. 1992 {"save-buffers-kill-emacs", "Quit the application.", 0, {quit}}, // Does more than just quit.
1993 {"forward-char", "Move cursor right one character.", 0, {rightChar}}, 1993 {"forward-char", "Move cursor right one character.", 0, {rightChar}},
1994 {"save-buffer", "Save.", 0, {saveContent}}, 1994 {"save-buffer", "Save.", 0, {saveContent}},
1995 {"split-window-horizontally", "Split box in half horizontally.", 0, {halveBoxHorizontally}}, // TODO - Making this one up for now, mg does not have it. 1995 {"split-window-horizontally", "Split box in half horizontally.", 0, {halveBoxHorizontally}}, // TODO - Making this one up for now, mg does not have it.
1996 {"newline", "Split line at cursor.", 0, {splitLine}}, 1996 {"newline", "Split line at cursor.", 0, {splitLine}},
1997 {"split-window-vertically", "Split box in half vertically.", 0, {halveBoxVertically}}, 1997 {"split-window-vertically", "Split box in half vertically.", 0, {halveBoxVertically}},
1998 {"beginning-of-line", "Go to start of line.", 0, {startOfLine}}, 1998 {"beginning-of-line", "Go to start of line.", 0, {startOfLine}},
1999 {"other-window", "Switch to another box.", 0, {switchBoxes}}, // There is also "previous-window" for going in the other direction, which we don't support yet. 1999 {"other-window", "Switch to another box.", 0, {switchBoxes}}, // There is also "previous-window" for going in the other direction, which we don't support yet.
2000 {"execute-extended-command", "Switch between command and box.", 0, {switchMode}}, // Actually a one time invocation of the command line. 2000 {"execute-extended-command", "Switch between command and box.", 0, {switchMode}}, // Actually a one time invocation of the command line.
2001 {"previous-line", "Move cursor up one line.", 0, {upLine}}, 2001 {"previous-line", "Move cursor up one line.", 0, {upLine}},
2002 {"scroll-down", "Move cursor up one page.", 0, {upPage}}, 2002 {"scroll-down", "Move cursor up one page.", 0, {upPage}},
2003 {NULL, NULL, 0, {NULL}} 2003 {NULL, NULL, 0, {NULL}}
2004}; 2004};
2005 2005
2006// The key to command mappings. 2006// The key to command mappings.
2007struct keyCommand simpleEmacsKeys[] = 2007struct keyCommand simpleEmacsKeys[] =
2008{ 2008{
2009 {"Del", "delete-backward-char"}, 2009 {"Del", "delete-backward-char"},
2010 {"^D", "delete-char"}, 2010 {"^D", "delete-char"},
2011 {"Down", "next-line"}, 2011 {"Down", "next-line"},
2012 {"^N", "next-line"}, 2012 {"^N", "next-line"},
2013 {"End", "end-of-line"}, 2013 {"End", "end-of-line"},
2014 {"^E", "end-of-line"}, 2014 {"^E", "end-of-line"},
2015 {"^X^C", "save-buffers-kill-emacs"}, // Damn, Ctrl C getting eaten by default signal handling. 2015 {"^X^C", "save-buffers-kill-emacs"}, // Damn, Ctrl C getting eaten by default signal handling.
2016 {"^Xq", "save-buffers-kill-emacs"}, // TODO - Faking this so we can actually exit. Remove it later. 2016 {"^Xq", "save-buffers-kill-emacs"}, // TODO - Faking this so we can actually exit. Remove it later.
2017 {"^X^S", "save-buffer"}, 2017 {"^X^S", "save-buffer"},
2018 {"Home", "beginning-of-line"}, 2018 {"Home", "beginning-of-line"},
2019 {"^A", "beginning-of-line"}, 2019 {"^A", "beginning-of-line"},
2020 {"Left", "backward-char"}, 2020 {"Left", "backward-char"},
2021 {"^B", "backward-char"}, 2021 {"^B", "backward-char"},
2022 {"PgDn", "scroll-up"}, 2022 {"PgDn", "scroll-up"},
2023 {"^V", "scroll-up"}, 2023 {"^V", "scroll-up"},
2024 {"PgUp", "scroll-down"}, 2024 {"PgUp", "scroll-down"},
2025 {"^[v", "scroll-down"}, // M-v 2025 {"^[v", "scroll-down"}, // M-v
2026 {"Return", "newline"}, 2026 {"Return", "newline"},
2027 {"Right", "forward-char"}, 2027 {"Right", "forward-char"},
2028 {"^F", "forward-char"}, 2028 {"^F", "forward-char"},
2029 {"^[x", "execute-extended-command"}, // M-x 2029 {"^[x", "execute-extended-command"}, // M-x
2030 {"^X2", "split-window-vertically"}, 2030 {"^X2", "split-window-vertically"},
2031 {"^X3", "split-window-horizontally"}, // TODO - Again, just making this up for now. 2031 {"^X3", "split-window-horizontally"}, // TODO - Again, just making this up for now.
2032 {"^XP", "other-window"}, 2032 {"^XP", "other-window"},
2033 {"^XP", "other-window"}, 2033 {"^XP", "other-window"},
2034 {"^X0", "delete-window"}, 2034 {"^X0", "delete-window"},
2035 {"Up", "previous-line"}, 2035 {"Up", "previous-line"},
2036 {"^P", "previous-line"}, 2036 {"^P", "previous-line"},
2037 {NULL, NULL} 2037 {NULL, NULL}
2038}; 2038};
2039 2039
2040struct keyCommand simpleEmacsCommandKeys[] = 2040struct keyCommand simpleEmacsCommandKeys[] =
2041{ 2041{
2042 {"Del", "delete-backwards-char"}, 2042 {"Del", "delete-backwards-char"},
2043 {"^D", "delete-char"}, 2043 {"^D", "delete-char"},
2044 {"^D", "delete-char"}, 2044 {"^D", "delete-char"},
2045 {"Down", "next-line"}, 2045 {"Down", "next-line"},
2046 {"^N", "next-line"}, 2046 {"^N", "next-line"},
2047 {"End", "end-of-line"}, 2047 {"End", "end-of-line"},
2048 {"^E", "end-of-line"}, 2048 {"^E", "end-of-line"},
2049 {"Home", "beginning-of-line"}, 2049 {"Home", "beginning-of-line"},
2050 {"^A", "beginning-of-line"}, 2050 {"^A", "beginning-of-line"},
2051 {"Left", "backward-char"}, 2051 {"Left", "backward-char"},
2052 {"^B", "backward-char"}, 2052 {"^B", "backward-char"},
2053 {"Up", "previous-line"}, 2053 {"Up", "previous-line"},
2054 {"^P", "previous-line"}, 2054 {"^P", "previous-line"},
2055 {"Return", "accept-line"}, 2055 {"Return", "accept-line"},
2056 {"^[x", "execute-extended-command"}, 2056 {"^[x", "execute-extended-command"},
2057 {NULL, NULL} 2057 {NULL, NULL}
2058}; 2058};
2059 2059
2060// An array of various modes. 2060// An array of various modes.
2061struct mode simpleEmacsMode[] = 2061struct mode simpleEmacsMode[] =
2062{ 2062{
2063 {simpleEmacsKeys, NULL, NULL, 0}, 2063 {simpleEmacsKeys, NULL, NULL, 0},
2064 {simpleEmacsCommandKeys, NULL, NULL, 1}, 2064 {simpleEmacsCommandKeys, NULL, NULL, 1},
2065 {NULL, NULL, NULL} 2065 {NULL, NULL, NULL}
2066}; 2066};
2067 2067
2068// Put it all together into a simple editor context. 2068// Put it all together into a simple editor context.
2069struct context simpleEmacs = 2069struct context simpleEmacs =
2070{ 2070{
2071 simpleEmacsCommands, 2071 simpleEmacsCommands,
2072 simpleEmacsMode, 2072 simpleEmacsMode,
2073 NULL, 2073 NULL,
2074 NULL, 2074 NULL,
2075 NULL 2075 NULL
2076}; 2076};
2077 2077
2078 2078
@@ -2087,95 +2087,95 @@ struct context simpleEmacs =
2087// TODO - Some of these might be wrong. Just going by the inadequate joe docs for now. 2087// TODO - Some of these might be wrong. Just going by the inadequate joe docs for now.
2088struct function simpleJoeCommands[] = 2088struct function simpleJoeCommands[] =
2089{ 2089{
2090 {"backs", "Back space last character.", 0, {backSpaceChar}}, 2090 {"backs", "Back space last character.", 0, {backSpaceChar}},
2091 {"abort", "Delete a box.", 0, {deleteBox}}, 2091 {"abort", "Delete a box.", 0, {deleteBox}},
2092 {"delch", "Delete current character.", 0, {deleteChar}}, 2092 {"delch", "Delete current character.", 0, {deleteChar}},
2093 {"dnarw", "Move cursor down one line.", 0, {downLine}}, 2093 {"dnarw", "Move cursor down one line.", 0, {downLine}},
2094 {"pgdn", "Move cursor down one page.", 0, {downPage}}, 2094 {"pgdn", "Move cursor down one page.", 0, {downPage}},
2095 {"eol", "Go to end of line.", 0, {endOfLine}}, 2095 {"eol", "Go to end of line.", 0, {endOfLine}},
2096 {"ltarw", "Move cursor left one character.", 0, {leftChar}}, 2096 {"ltarw", "Move cursor left one character.", 0, {leftChar}},
2097 {"killjoe", "Quit the application.", 0, {quit}}, 2097 {"killjoe", "Quit the application.", 0, {quit}},
2098 {"rtarw", "Move cursor right one character.", 0, {rightChar}}, 2098 {"rtarw", "Move cursor right one character.", 0, {rightChar}},
2099 {"save", "Save.", 0, {saveContent}}, 2099 {"save", "Save.", 0, {saveContent}},
2100 {"splitw", "Split box in half horizontally.", 0, {halveBoxHorizontally}}, 2100 {"splitw", "Split box in half horizontally.", 0, {halveBoxHorizontally}},
2101 {"open", "Split line at cursor.", 0, {splitLine}}, 2101 {"open", "Split line at cursor.", 0, {splitLine}},
2102 {"bol", "Go to start of line.", 0, {startOfLine}}, 2102 {"bol", "Go to start of line.", 0, {startOfLine}},
2103 {"home", "Go to start of line.", 0, {startOfLine}}, 2103 {"home", "Go to start of line.", 0, {startOfLine}},
2104 {"nextw", "Switch to another box.", 0, {switchBoxes}}, // This is "next window", there's also "previous window" which we don't support yet. 2104 {"nextw", "Switch to another box.", 0, {switchBoxes}}, // This is "next window", there's also "previous window" which we don't support yet.
2105 {"execmd", "Switch between command and box.", 0, {switchMode}}, // Actually I think this just switches to the command mode, not back and forth. Or it might execute the actual command. 2105 {"execmd", "Switch between command and box.", 0, {switchMode}}, // Actually I think this just switches to the command mode, not back and forth. Or it might execute the actual command.
2106 {"uparw", "Move cursor up one line.", 0, {upLine}}, 2106 {"uparw", "Move cursor up one line.", 0, {upLine}},
2107 {"pgup", "Move cursor up one page.", 0, {upPage}}, 2107 {"pgup", "Move cursor up one page.", 0, {upPage}},
2108 2108
2109 // Not an actual joe command. 2109 // Not an actual joe command.
2110 {"executeLine", "Execute a line as a script.", 0, {executeLine}}, // Perhaps this should be execmd? 2110 {"executeLine", "Execute a line as a script.", 0, {executeLine}}, // Perhaps this should be execmd?
2111 {NULL, NULL, 0, {NULL}} 2111 {NULL, NULL, 0, {NULL}}
2112}; 2112};
2113 2113
2114struct keyCommand simpleJoeKeys[] = 2114struct keyCommand simpleJoeKeys[] =
2115{ 2115{
2116 {"BS", "backs"}, 2116 {"BS", "backs"},
2117 {"^D", "delch"}, 2117 {"^D", "delch"},
2118 {"Down", "dnarw"}, 2118 {"Down", "dnarw"},
2119 {"^N", "dnarw"}, 2119 {"^N", "dnarw"},
2120 {"^E", "eol"}, 2120 {"^E", "eol"},
2121// {"F10", "killjoe"}, // "deleteBox" should do this if it's the last window. 2121// {"F10", "killjoe"}, // "deleteBox" should do this if it's the last window.
2122 {"^Kd", "save"}, 2122 {"^Kd", "save"},
2123 {"^K^D" "save"}, 2123 {"^K^D" "save"},
2124 {"^A", "bol"}, 2124 {"^A", "bol"},
2125 {"Left", "ltarw"}, 2125 {"Left", "ltarw"},
2126 {"^B", "ltarw"}, 2126 {"^B", "ltarw"},
2127 {"^V", "pgdn"}, // Actually half a page. 2127 {"^V", "pgdn"}, // Actually half a page.
2128 {"^U", "pgup"}, // Actually half a page. 2128 {"^U", "pgup"}, // Actually half a page.
2129 {"Return", "open"}, 2129 {"Return", "open"},
2130 {"Right", "rtarw"}, 2130 {"Right", "rtarw"},
2131 {"^F", "rtarw"}, 2131 {"^F", "rtarw"},
2132 {"^[x", "execmd"}, 2132 {"^[x", "execmd"},
2133 {"^[^X", "execmd"}, 2133 {"^[^X", "execmd"},
2134 {"^Ko", "splitw"}, 2134 {"^Ko", "splitw"},
2135 {"^K^O", "splitw"}, 2135 {"^K^O", "splitw"},
2136 {"^Kn", "nextw"}, 2136 {"^Kn", "nextw"},
2137 {"^K^N", "nextw"}, 2137 {"^K^N", "nextw"},
2138 {"^Kx", "abort"}, // Should ask if it should save if it's been modified. A good generic thing to do anyway. 2138 {"^Kx", "abort"}, // Should ask if it should save if it's been modified. A good generic thing to do anyway.
2139 {"^K^X", "abort"}, 2139 {"^K^X", "abort"},
2140 {"Up", "uparw"}, 2140 {"Up", "uparw"},
2141 {"^P", "uparw"}, 2141 {"^P", "uparw"},
2142 {NULL, NULL} 2142 {NULL, NULL}
2143}; 2143};
2144 2144
2145struct keyCommand simpleJoeCommandKeys[] = 2145struct keyCommand simpleJoeCommandKeys[] =
2146{ 2146{
2147 {"BS", "backs"}, 2147 {"BS", "backs"},
2148 {"^D", "delch"}, 2148 {"^D", "delch"},
2149 {"Down", "dnarw"}, 2149 {"Down", "dnarw"},
2150 {"^N", "dnarw"}, 2150 {"^N", "dnarw"},
2151 {"^E", "eol"}, 2151 {"^E", "eol"},
2152 {"^A", "bol"}, 2152 {"^A", "bol"},
2153 {"Left", "ltarw"}, 2153 {"Left", "ltarw"},
2154 {"^B", "ltarw"}, 2154 {"^B", "ltarw"},
2155 {"Right", "rtarw"}, 2155 {"Right", "rtarw"},
2156 {"^F", "rtarw"}, 2156 {"^F", "rtarw"},
2157 {"^[x", "execmd"}, 2157 {"^[x", "execmd"},
2158 {"^[^X", "execmd"}, 2158 {"^[^X", "execmd"},
2159 {"Up", "uparw"}, 2159 {"Up", "uparw"},
2160 {"^P", "uparw"}, 2160 {"^P", "uparw"},
2161 {"Return", "executeLine"}, 2161 {"Return", "executeLine"},
2162 {NULL, NULL} 2162 {NULL, NULL}
2163}; 2163};
2164 2164
2165struct mode simpleJoeMode[] = 2165struct mode simpleJoeMode[] =
2166{ 2166{
2167 {simpleJoeKeys, NULL, NULL, 0}, 2167 {simpleJoeKeys, NULL, NULL, 0},
2168 {simpleJoeCommandKeys, NULL, NULL, 1}, 2168 {simpleJoeCommandKeys, NULL, NULL, 1},
2169 {NULL, NULL, NULL, 0} 2169 {NULL, NULL, NULL, 0}
2170}; 2170};
2171 2171
2172struct context simpleJoe = 2172struct context simpleJoe =
2173{ 2173{
2174 simpleJoeCommands, 2174 simpleJoeCommands,
2175 simpleJoeMode, 2175 simpleJoeMode,
2176 NULL, 2176 NULL,
2177 NULL, 2177 NULL,
2178 NULL 2178 NULL
2179}; 2179};
2180 2180
2181 2181
@@ -2187,73 +2187,73 @@ struct context simpleJoe =
2187 2187
2188struct keyCommand simpleLessKeys[] = 2188struct keyCommand simpleLessKeys[] =
2189{ 2189{
2190 {"Down", "downLine"}, 2190 {"Down", "downLine"},
2191 {"j", "downLine"}, 2191 {"j", "downLine"},
2192 {"Return", "downLine"}, 2192 {"Return", "downLine"},
2193 {"End", "endOfLine"}, 2193 {"End", "endOfLine"},
2194 {"q", "quit"}, 2194 {"q", "quit"},
2195 {":q", "quit"}, 2195 {":q", "quit"},
2196 {"ZZ", "quit"}, 2196 {"ZZ", "quit"},
2197 {"PgDn", "downPage"}, 2197 {"PgDn", "downPage"},
2198 {"f", "downPage"}, 2198 {"f", "downPage"},
2199 {" ", "downPage"}, 2199 {" ", "downPage"},
2200 {"^F", "downPage"}, 2200 {"^F", "downPage"},
2201 {"Left", "leftChar"}, 2201 {"Left", "leftChar"},
2202 {"Right", "rightChar"}, 2202 {"Right", "rightChar"},
2203 {"PgUp", "upPage"}, 2203 {"PgUp", "upPage"},
2204 {"b", "upPage"}, 2204 {"b", "upPage"},
2205 {"^B", "upPage"}, 2205 {"^B", "upPage"},
2206 {"Up", "upLine"}, 2206 {"Up", "upLine"},
2207 {"k", "upLine"}, 2207 {"k", "upLine"},
2208 {NULL, NULL} 2208 {NULL, NULL}
2209}; 2209};
2210 2210
2211struct mode simpleLessMode[] = 2211struct mode simpleLessMode[] =
2212{ 2212{
2213 {simpleLessKeys, NULL, NULL, 0}, 2213 {simpleLessKeys, NULL, NULL, 0},
2214 {simpleCommandKeys, NULL, NULL, 1}, 2214 {simpleCommandKeys, NULL, NULL, 1},
2215 {NULL, NULL, NULL} 2215 {NULL, NULL, NULL}
2216}; 2216};
2217 2217
2218struct context simpleLess = 2218struct context simpleLess =
2219{ 2219{
2220 simpleEditCommands, 2220 simpleEditCommands,
2221 simpleLessMode, 2221 simpleLessMode,
2222 NULL, 2222 NULL,
2223 NULL, 2223 NULL,
2224 NULL 2224 NULL
2225}; 2225};
2226 2226
2227struct keyCommand simpleMoreKeys[] = 2227struct keyCommand simpleMoreKeys[] =
2228{ 2228{
2229 {"j", "downLine"}, 2229 {"j", "downLine"},
2230 {"Return", "downLine"}, 2230 {"Return", "downLine"},
2231 {"q", "quit"}, 2231 {"q", "quit"},
2232 {":q", "quit"}, 2232 {":q", "quit"},
2233 {"ZZ", "quit"}, 2233 {"ZZ", "quit"},
2234 {"f", "downPage"}, 2234 {"f", "downPage"},
2235 {" ", "downPage"}, 2235 {" ", "downPage"},
2236 {"^F", "downPage"}, 2236 {"^F", "downPage"},
2237 {"b", "upPage"}, 2237 {"b", "upPage"},
2238 {"^B", "upPage"}, 2238 {"^B", "upPage"},
2239 {"k", "upLine"}, 2239 {"k", "upLine"},
2240 {NULL, NULL} 2240 {NULL, NULL}
2241}; 2241};
2242 2242
2243struct mode simpleMoreMode[] = 2243struct mode simpleMoreMode[] =
2244{ 2244{
2245 {simpleMoreKeys, NULL, NULL, 0}, 2245 {simpleMoreKeys, NULL, NULL, 0},
2246 {simpleCommandKeys, NULL, NULL, 1}, 2246 {simpleCommandKeys, NULL, NULL, 1},
2247 {NULL, NULL, NULL} 2247 {NULL, NULL, NULL}
2248}; 2248};
2249 2249
2250struct context simpleMore = 2250struct context simpleMore =
2251{ 2251{
2252 simpleEditCommands, 2252 simpleEditCommands,
2253 simpleMoreMode, 2253 simpleMoreMode,
2254 NULL, 2254 NULL,
2255 NULL, 2255 NULL,
2256 NULL 2256 NULL
2257}; 2257};
2258 2258
2259 2259
@@ -2261,45 +2261,45 @@ struct context simpleMore =
2261 2261
2262struct keyCommand simpleMceditKeys[] = 2262struct keyCommand simpleMceditKeys[] =
2263{ 2263{
2264 {"BS", "backSpaceChar"}, 2264 {"BS", "backSpaceChar"},
2265 {"Del", "deleteChar"}, 2265 {"Del", "deleteChar"},
2266 {"Down", "downLine"}, 2266 {"Down", "downLine"},
2267 {"End", "endOfLine"}, 2267 {"End", "endOfLine"},
2268 {"F10", "quit"}, 2268 {"F10", "quit"},
2269 {"^[0", "quit"}, 2269 {"^[0", "quit"},
2270 {"F2", "save"}, 2270 {"F2", "save"},
2271 {"^[2", "save"}, 2271 {"^[2", "save"},
2272 {"Home", "startOfLine"}, 2272 {"Home", "startOfLine"},
2273 {"Left", "leftChar"}, 2273 {"Left", "leftChar"},
2274 {"PgDn", "downPage"}, 2274 {"PgDn", "downPage"},
2275 {"PgUp", "upPage"}, 2275 {"PgUp", "upPage"},
2276 {"Return", "splitLine"}, 2276 {"Return", "splitLine"},
2277 {"Right", "rightChar"}, 2277 {"Right", "rightChar"},
2278 {"Shift F2", "switchMode"}, 2278 {"Shift F2", "switchMode"}, // MC doesn't have a command mode.
2279 {"^[x", "switchMode"}, // Emacs like. 2279 {"^[x", "switchMode"}, // Emacs like.
2280 {"^[:", "switchMode"}, // Sorta vi like. 2280 {"^[:", "switchMode"}, // Sorta vi like.
2281 {"^O|", "splitV"}, // MC doesn't have a split window concept, so make these up to match tmux more or less. 2281 {"^O|", "splitV"}, // MC doesn't have a split window concept, so make these up to match tmux more or less.
2282 {"^O-", "splitH"}, 2282 {"^O-", "splitH"},
2283 {"^Oo", "switchBoxes"}, 2283 {"^Oo", "switchBoxes"},
2284 {"^Ox", "deleteBox"}, 2284 {"^Ox", "deleteBox"},
2285 {"Up", "upLine"}, 2285 {"Up", "upLine"},
2286 {NULL, NULL} 2286 {NULL, NULL}
2287}; 2287};
2288 2288
2289struct mode simpleMceditMode[] = 2289struct mode simpleMceditMode[] =
2290{ 2290{
2291 {simpleMceditKeys, NULL, NULL, 0}, 2291 {simpleMceditKeys, NULL, NULL, 0},
2292 {simpleCommandKeys, NULL, NULL, 1}, 2292 {simpleCommandKeys, NULL, NULL, 1},
2293 {NULL, NULL, NULL} 2293 {NULL, NULL, NULL}
2294}; 2294};
2295 2295
2296struct context simpleMcedit = 2296struct context simpleMcedit =
2297{ 2297{
2298 simpleEditCommands, 2298 simpleEditCommands,
2299 simpleMceditMode, 2299 simpleMceditMode,
2300 NULL, 2300 NULL,
2301 NULL, 2301 NULL,
2302 NULL 2302 NULL
2303}; 2303};
2304 2304
2305 2305
@@ -2310,20 +2310,20 @@ struct context simpleMcedit =
2310 2310
2311struct function simpleNanoCommands[] = 2311struct function simpleNanoCommands[] =
2312{ 2312{
2313 {"backSpaceChar","Back space last character.", 0, {backSpaceChar}}, 2313 {"backSpaceChar", "Back space last character.", 0, {backSpaceChar}},
2314 {"delete", "Delete current character.", 0, {deleteChar}}, 2314 {"delete", "Delete current character.", 0, {deleteChar}},
2315 {"down", "Move cursor down one line.", 0, {downLine}}, 2315 {"down", "Move cursor down one line.", 0, {downLine}},
2316 {"downPage", "Move cursor down one page.", 0, {downPage}}, 2316 {"downPage", "Move cursor down one page.", 0, {downPage}},
2317 {"end", "Go to end of line.", 0, {endOfLine}}, 2317 {"end", "Go to end of line.", 0, {endOfLine}},
2318 {"left", "Move cursor left one character.", 0, {leftChar}}, 2318 {"left", "Move cursor left one character.", 0, {leftChar}},
2319 {"exit", "Quit the application.", 0, {quit}}, 2319 {"exit", "Quit the application.", 0, {quit}},
2320 {"right", "Move cursor right one character.", 0, {rightChar}}, 2320 {"right", "Move cursor right one character.", 0, {rightChar}},
2321 {"writeout", "Save.", 0, {saveContent}}, 2321 {"writeout", "Save.", 0, {saveContent}},
2322 {"enter", "Split line at cursor.", 0, {splitLine}}, 2322 {"enter", "Split line at cursor.", 0, {splitLine}},
2323 {"home", "Go to start of line.", 0, {startOfLine}}, 2323 {"home", "Go to start of line.", 0, {startOfLine}},
2324 {"up", "Move cursor up one line.", 0, {upLine}}, 2324 {"up", "Move cursor up one line.", 0, {upLine}},
2325 {"upPage", "Move cursor up one page.", 0, {upPage}}, 2325 {"upPage", "Move cursor up one page.", 0, {upPage}},
2326 {NULL, NULL, 0, {NULL}} 2326 {NULL, NULL, 0, {NULL}}
2327}; 2327};
2328 2328
2329 2329
@@ -2331,51 +2331,52 @@ struct function simpleNanoCommands[] =
2331struct keyCommand simpleNanoKeys[] = 2331struct keyCommand simpleNanoKeys[] =
2332{ 2332{
2333// TODO - Delete key is ^H dammit. Find the alternate Esc sequence for Del. 2333// TODO - Delete key is ^H dammit. Find the alternate Esc sequence for Del.
2334// {"^H", "backSpaceChar"}, // ? 2334// {"^H", "backSpaceChar"}, // ?
2335 {"BS", "backSpaceChar"}, 2335 {"BS", "backSpaceChar"},
2336 {"^D", "delete"}, 2336 {"^D", "delete"},
2337 {"Del", "delete"}, 2337 {"Del", "delete"},
2338 {"^N", "down"}, 2338 {"^N", "down"},
2339 {"Down", "down"}, 2339 {"Down", "down"},
2340 {"^E", "end"}, 2340 {"^E", "end"},
2341 {"End", "end"}, 2341 {"End", "end"},
2342 {"^X", "exit"}, 2342 {"^X", "exit"},
2343 {"F2", "quit"}, 2343 {"F2", "quit"},
2344 {"^O", "writeout"}, 2344 {"^O", "writeout"},
2345 {"F3", "writeout"}, 2345 {"F3", "writeout"},
2346 {"^A", "home"}, 2346 {"^A", "home"},
2347 {"Home", "home"}, 2347 {"Home", "home"},
2348 {"^B", "left"}, 2348 {"^B", "left"},
2349 {"Left", "left"}, 2349 {"Left", "left"},
2350 {"^V", "downPage"}, // ? 2350 {"^V", "downPage"}, // ?
2351 {"PgDn", "downPage"}, 2351 {"PgDn", "downPage"},
2352 {"^Y", "upPage"}, // ? 2352 {"^Y", "upPage"}, // ?
2353 {"PgUp", "upPage"}, 2353 {"PgUp", "upPage"},
2354 {"Return", "enter"}, // TODO - Not sure if this is correct. 2354 {"Return", "enter"}, // TODO - Not sure if this is correct.
2355 {"^F", "right"}, 2355 {"^F", "right"},
2356 {"Right", "right"}, 2356 {"Right", "right"},
2357 {"^P", "up"}, 2357 {"^P", "up"},
2358 {"Up", "up"}, 2358 {"Up", "up"},
2359 {NULL, NULL} 2359 {NULL, NULL}
2360}; 2360};
2361 2361
2362struct mode simpleNanoMode[] = 2362struct mode simpleNanoMode[] =
2363{ 2363{
2364 {simpleNanoKeys, NULL, NULL, 0}, 2364 {simpleNanoKeys, NULL, NULL, 0},
2365 {NULL, NULL, NULL} 2365 {NULL, NULL, NULL}
2366}; 2366};
2367 2367
2368struct context simpleNano = 2368struct context simpleNano =
2369{ 2369{
2370 simpleNanoCommands, 2370 simpleNanoCommands,
2371 simpleNanoMode, 2371 simpleNanoMode,
2372 NULL, 2372 NULL,
2373 NULL, 2373 NULL,
2374 NULL 2374 NULL
2375}; 2375};
2376 2376
2377 2377
2378// Construct a simple vi editor. 2378// Construct a simple vi editor.
2379// Only vi is not so sibple. lol
2379// The "command line" modes are /, ?, :, and !, 2380// The "command line" modes are /, ?, :, and !,
2380// / is regex search. 2381// / is regex search.
2381// ? is regex search backwards. 2382// ? is regex search backwards.
@@ -2405,148 +2406,148 @@ static int viTempExMode;
2405 2406
2406void viMode(view *view, event *event) 2407void viMode(view *view, event *event)
2407{ 2408{
2408 currentBox->view->mode = 0; 2409 currentBox->view->mode = 0;
2409 commandMode = 0; 2410 commandMode = 0;
2410 viTempExMode = 0; 2411 viTempExMode = 0;
2411} 2412}
2412 2413
2413void viInsertMode(view *view, event *event) 2414void viInsertMode(view *view, event *event)
2414{ 2415{
2415 currentBox->view->mode = 1; 2416 currentBox->view->mode = 1;
2416 commandMode = 0; 2417 commandMode = 0;
2417} 2418}
2418 2419
2419void viExMode(view *view, event *event) 2420void viExMode(view *view, event *event)
2420{ 2421{
2421 currentBox->view->mode = 2; 2422 currentBox->view->mode = 2;
2422 commandMode = 1; 2423 commandMode = 1;
2423 // TODO - Should change this based on the event, : or Q. 2424 // TODO - Should change this based on the event, : or Q.
2424 viTempExMode = 1; 2425 viTempExMode = 1;
2425 commandLine->prompt = xrealloc(commandLine->prompt, 2); 2426 commandLine->prompt = xrealloc(commandLine->prompt, 2);
2426 strcpy(commandLine->prompt, ":"); 2427 strcpy(commandLine->prompt, ":");
2427} 2428}
2428 2429
2429void viBackSpaceChar(view *view, event *event) 2430void viBackSpaceChar(view *view, event *event)
2430{ 2431{
2431 if ((2 == currentBox->view->mode) && (0 == view->cX) && viTempExMode) 2432 if ((2 == currentBox->view->mode) && (0 == view->cX) && viTempExMode)
2432 viMode(view, event); 2433 viMode(view, event);
2433 else 2434 else
2434 backSpaceChar(view, event); 2435 backSpaceChar(view, event);
2435} 2436}
2436 2437
2437void viStartOfNextLine(view *view, event *event) 2438void viStartOfNextLine(view *view, event *event)
2438{ 2439{
2439 startOfLine(view, event); 2440 startOfLine(view, event);
2440 downLine(view, event); 2441 downLine(view, event);
2441} 2442}
2442 2443
2443// TODO - ex uses "shortest unique string" to match commands, should implement that, and do it for the other contexts to. 2444// TODO - ex uses "shortest unique string" to match commands, should implement that, and do it for the other contexts to.
2444struct function simpleViCommands[] = 2445struct function simpleViCommands[] =
2445{ 2446{
2446 // These are actual ex commands. 2447 // These are actual ex commands.
2447 {"insert", "Switch to insert mode.", 0, {viInsertMode}}, 2448 {"insert", "Switch to insert mode.", 0, {viInsertMode}},
2448 {"quit", "Quit the application.", 0, {quit}}, 2449 {"quit", "Quit the application.", 0, {quit}},
2449 {"visual", "Switch to visual mode.", 0, {viMode}}, 2450 {"visual", "Switch to visual mode.", 0, {viMode}},
2450 {"write", "Save.", 0, {saveContent}}, 2451 {"write", "Save.", 0, {saveContent}},
2451 2452
2452 // These are not ex commands. 2453 // These are not ex commands.
2453 {"backSpaceChar","Back space last character.", 0, {viBackSpaceChar}}, 2454 {"backSpaceChar", "Back space last character.", 0, {viBackSpaceChar}},
2454 {"deleteBox", "Delete a box.", 0, {deleteBox}}, 2455 {"deleteBox", "Delete a box.", 0, {deleteBox}},
2455 {"deleteChar", "Delete current character.", 0, {deleteChar}}, 2456 {"deleteChar", "Delete current character.", 0, {deleteChar}},
2456 {"downLine", "Move cursor down one line.", 0, {downLine}}, 2457 {"downLine", "Move cursor down one line.", 0, {downLine}},
2457 {"downPage", "Move cursor down one page.", 0, {downPage}}, 2458 {"downPage", "Move cursor down one page.", 0, {downPage}},
2458 {"endOfLine", "Go to end of line.", 0, {endOfLine}}, 2459 {"endOfLine", "Go to end of line.", 0, {endOfLine}},
2459 {"executeLine", "Execute a line as a script.", 0, {executeLine}}, 2460 {"executeLine", "Execute a line as a script.", 0, {executeLine}},
2460 {"exMode", "Switch to ex mode.", 0, {viExMode}}, 2461 {"exMode", "Switch to ex mode.", 0, {viExMode}},
2461 {"leftChar", "Move cursor left one character.", 0, {leftChar}}, 2462 {"leftChar", "Move cursor left one character.", 0, {leftChar}},
2462 {"rightChar", "Move cursor right one character.", 0, {rightChar}}, 2463 {"rightChar", "Move cursor right one character.", 0, {rightChar}},
2463 {"splitH", "Split box in half horizontally.", 0, {halveBoxHorizontally}}, 2464 {"splitH", "Split box in half horizontally.", 0, {halveBoxHorizontally}},
2464 {"splitLine", "Split line at cursor.", 0, {splitLine}}, 2465 {"splitLine", "Split line at cursor.", 0, {splitLine}},
2465 {"splitV", "Split box in half vertically.", 0, {halveBoxVertically}}, 2466 {"splitV", "Split box in half vertically.", 0, {halveBoxVertically}},
2466 {"startOfLine", "Go to start of line.", 0, {startOfLine}}, 2467 {"startOfLine", "Go to start of line.", 0, {startOfLine}},
2467 {"startOfNLine","Go to start of next line.", 0, {viStartOfNextLine}}, 2468 {"startOfNLine", "Go to start of next line.", 0, {viStartOfNextLine}},
2468 {"switchBoxes", "Switch to another box.", 0, {switchBoxes}}, 2469 {"switchBoxes", "Switch to another box.", 0, {switchBoxes}},
2469 {"upLine", "Move cursor up one line.", 0, {upLine}}, 2470 {"upLine", "Move cursor up one line.", 0, {upLine}},
2470 {"upPage", "Move cursor up one page.", 0, {upPage}}, 2471 {"upPage", "Move cursor up one page.", 0, {upPage}},
2471 {NULL, NULL, 0, {NULL}} 2472 {NULL, NULL, 0, {NULL}}
2472}; 2473};
2473 2474
2474struct keyCommand simpleViNormalKeys[] = 2475struct keyCommand simpleViNormalKeys[] =
2475{ 2476{
2476 {"BS", "leftChar"}, 2477 {"BS", "leftChar"},
2477 {"X", "backSpaceChar"}, 2478 {"X", "backSpaceChar"},
2478 {"Del", "deleteChar"}, 2479 {"Del", "deleteChar"},
2479 {"x", "deleteChar"}, 2480 {"x", "deleteChar"},
2480 {"Down", "downLine"}, 2481 {"Down", "downLine"},
2481 {"j", "downLine"}, 2482 {"j", "downLine"},
2482 {"End", "endOfLine"}, 2483 {"End", "endOfLine"},
2483 {"Home", "startOfLine"}, 2484 {"Home", "startOfLine"},
2484 {"Left", "leftChar"}, 2485 {"Left", "leftChar"},
2485 {"h", "leftChar"}, 2486 {"h", "leftChar"},
2486 {"PgDn", "downPage"}, 2487 {"PgDn", "downPage"},
2487 {"^F", "downPage"}, 2488 {"^F", "downPage"},
2488 {"PgUp", "upPage"}, 2489 {"PgUp", "upPage"},
2489 {"^B", "upPage"}, 2490 {"^B", "upPage"},
2490 {"Return", "startOfNextLine"}, 2491 {"Return", "startOfNextLine"},
2491 {"Right", "rightChar"}, 2492 {"Right", "rightChar"},
2492 {"l", "rightChar"}, 2493 {"l", "rightChar"},
2493 {"i", "insert"}, 2494 {"i", "insert"},
2494 {":", "exMode"}, // This is the temporary ex mode that you can backspace out of. Or any command backs you out. 2495 {":", "exMode"}, // This is the temporary ex mode that you can backspace out of. Or any command backs you out.
2495 {"Q", "exMode"}, // This is the ex mode you need to do the "visual" command to get out of. 2496 {"Q", "exMode"}, // This is the ex mode you need to do the "visual" command to get out of.
2496 {"^Wv", "splitV"}, 2497 {"^Wv", "splitV"},
2497 {"^W^V", "splitV"}, 2498 {"^W^V", "splitV"},
2498 {"^Ws", "splitH"}, 2499 {"^Ws", "splitH"},
2499 {"^WS", "splitH"}, 2500 {"^WS", "splitH"},
2500 {"^W^S", "splitH"}, 2501 {"^W^S", "splitH"},
2501 {"^Ww", "switchBoxes"}, 2502 {"^Ww", "switchBoxes"},
2502 {"^W^W", "switchBoxes"}, 2503 {"^W^W", "switchBoxes"},
2503 {"^Wq", "deleteBox"}, 2504 {"^Wq", "deleteBox"},
2504 {"^W^Q", "deleteBox"}, 2505 {"^W^Q", "deleteBox"},
2505 {"Up", "upLine"}, 2506 {"Up", "upLine"},
2506 {"k", "upLine"}, 2507 {"k", "upLine"},
2507 {NULL, NULL} 2508 {NULL, NULL}
2508}; 2509};
2509 2510
2510struct keyCommand simpleViInsertKeys[] = 2511struct keyCommand simpleViInsertKeys[] =
2511{ 2512{
2512 {"BS", "backSpaceChar"}, 2513 {"BS", "backSpaceChar"},
2513 {"Del", "deleteChar"}, 2514 {"Del", "deleteChar"},
2514 {"Return", "splitLine"}, 2515 {"Return", "splitLine"},
2515 {"^[", "visual"}, 2516 {"^[", "visual"},
2516 {"^C", "visual"}, // TODO - Ctrl-C is filtered by the default signal handling, which we might want to disable. 2517 {"^C", "visual"}, // TODO - Ctrl-C is filtered by the default signal handling, which we might want to disable.
2517 {NULL, NULL} 2518 {NULL, NULL}
2518}; 2519};
2519 2520
2520struct keyCommand simpleExKeys[] = 2521struct keyCommand simpleExKeys[] =
2521{ 2522{
2522 {"BS", "backSpaceChar"}, 2523 {"BS", "backSpaceChar"},
2523 {"Del", "deleteChar"}, 2524 {"Del", "deleteChar"},
2524 {"Down", "downLine"}, 2525 {"Down", "downLine"},
2525 {"End", "endOfLine"}, 2526 {"End", "endOfLine"},
2526 {"Home", "startOfLine"}, 2527 {"Home", "startOfLine"},
2527 {"Left", "leftChar"}, 2528 {"Left", "leftChar"},
2528 {"Return", "executeLine"}, 2529 {"Return", "executeLine"},
2529 {"Right", "rightChar"}, 2530 {"Right", "rightChar"},
2530 {"^[", "visual"}, 2531 {"^[", "visual"},
2531 {"Up", "upLine"}, 2532 {"Up", "upLine"},
2532 {NULL, NULL} 2533 {NULL, NULL}
2533}; 2534};
2534 2535
2535struct mode simpleViMode[] = 2536struct mode simpleViMode[] =
2536{ 2537{
2537 {simpleViNormalKeys, NULL, NULL, 0}, 2538 {simpleViNormalKeys, NULL, NULL, 0},
2538 {simpleViInsertKeys, NULL, NULL, 0}, 2539 {simpleViInsertKeys, NULL, NULL, 0},
2539 {simpleExKeys, NULL, NULL, 1}, 2540 {simpleExKeys, NULL, NULL, 1},
2540 {NULL, NULL, NULL} 2541 {NULL, NULL, NULL}
2541}; 2542};
2542 2543
2543struct context simpleVi = 2544struct context simpleVi =
2544{ 2545{
2545 simpleViCommands, 2546 simpleViCommands,
2546 simpleViMode, 2547 simpleViMode,
2547 NULL, 2548 NULL,
2548 NULL, 2549 NULL,
2549 NULL 2550 NULL
2550}; 2551};
2551 2552
2552 2553
@@ -2560,59 +2561,59 @@ struct context simpleVi =
2560 2561
2561void boxes_main(void) 2562void boxes_main(void)
2562{ 2563{
2563 struct context *context = &simpleMcedit; // The default is mcedit, coz that's what I use. 2564 struct context *context = &simpleMcedit; // The default is mcedit, coz that's what I use.
2564 char *prompt = "Enter a command : "; 2565 char *prompt = "Enter a command : ";
2565 unsigned W = 80, H = 24; 2566 unsigned W = 80, H = 24;
2566 2567
2567 // TODO - Should do an isatty() here, though not sure about the usefullness of driving this from a script or redirected input, since it's supposed to be a UI for terminals. 2568 // TODO - Should do an isatty() here, though not sure about the usefullness of driving this from a script or redirected input, since it's supposed to be a UI for terminals.
2568 // It would STILL need the terminal size for output though. Perhaps just bitch and abort if it's not a tty? 2569 // It would STILL need the terminal size for output though. Perhaps just bitch and abort if it's not a tty?
2569 // On the other hand, sed don't need no stinkin' UI. And things like more or less should be usable on the end of a pipe. 2570 // On the other hand, sed don't need no stinkin' UI. And things like more or less should be usable on the end of a pipe.
2570 2571
2571 // TODO - set up a handler for SIGWINCH to find out when the terminal has been resized. 2572 // TODO - set up a handler for SIGWINCH to find out when the terminal has been resized.
2572 terminal_size(&W, &H); 2573 terminal_size(&W, &H);
2573 if (toys.optflags & FLAG_w) 2574 if (toys.optflags & FLAG_w)
2574 W = TT.w; 2575 W = TT.w;
2575 if (toys.optflags & FLAG_h) 2576 if (toys.optflags & FLAG_h)
2576 H = TT.h; 2577 H = TT.h;
2577 2578
2578 TT.stillRunning = 1; 2579 TT.stillRunning = 1;
2579 2580
2580 // For testing purposes, figure out which context we use. When this gets real, the toybox multiplexer will sort this out for us instead. 2581 // For testing purposes, figure out which context we use. When this gets real, the toybox multiplexer will sort this out for us instead.
2581 if (toys.optflags & FLAG_m) 2582 if (toys.optflags & FLAG_m)
2582 { 2583 {
2583 if (strcmp(TT.mode, "emacs") == 0) 2584 if (strcmp(TT.mode, "emacs") == 0)
2584 context = &simpleEmacs; 2585 context = &simpleEmacs;
2585 else if (strcmp(TT.mode, "joe") == 0) 2586 else if (strcmp(TT.mode, "joe") == 0)
2586 context = &simpleJoe; 2587 context = &simpleJoe;
2587 else if (strcmp(TT.mode, "less") == 0) 2588 else if (strcmp(TT.mode, "less") == 0)
2588 context = &simpleLess; 2589 context = &simpleLess;
2589 else if (strcmp(TT.mode, "mcedit") == 0) 2590 else if (strcmp(TT.mode, "mcedit") == 0)
2590 context = &simpleMcedit; 2591 context = &simpleMcedit;
2591 else if (strcmp(TT.mode, "more") == 0) 2592 else if (strcmp(TT.mode, "more") == 0)
2592 context = &simpleMore; 2593 context = &simpleMore;
2593 else if (strcmp(TT.mode, "nano") == 0) 2594 else if (strcmp(TT.mode, "nano") == 0)
2594 context = &simpleNano; 2595 context = &simpleNano;
2595 else if (strcmp(TT.mode, "vi") == 0) 2596 else if (strcmp(TT.mode, "vi") == 0)
2596 context = &simpleVi; 2597 context = &simpleVi;
2597 } 2598 }
2598 2599
2599 // Create the main box. Right now the system needs one for wrapping around while switching. The H - 1 bit is to leave room for our example command line. 2600 // Create the main box. Right now the system needs one for wrapping around while switching. The H - 1 bit is to leave room for our example command line.
2600 rootBox = addBox("root", context, toys.optargs[0], 0, 0, W, H - 1); 2601 rootBox = addBox("root", context, toys.optargs[0], 0, 0, W, H - 1);
2601 2602
2602 // Create the command line view, sharing the same context as the root. It will differentiate based on the view mode of the current box. 2603 // Create the command line view, sharing the same context as the root. It will differentiate based on the view mode of the current box.
2603 // Also load the command line history as it's file. 2604 // Also load the command line history as it's file.
2604 // TODO - different contexts will have different history files, though what to do about ones with no history, and ones with different histories for different modes? 2605 // TODO - different contexts will have different history files, though what to do about ones with no history, and ones with different histories for different modes?
2605 commandLine = addView("command", rootBox->view->content->context, ".boxes.history", 0, H, W, 1); 2606 commandLine = addView("command", rootBox->view->content->context, ".boxes.history", 0, H, W, 1);
2606 // Add a prompt to it. 2607 // Add a prompt to it.
2607 commandLine->prompt = xrealloc(commandLine->prompt, strlen(prompt) + 1); 2608 commandLine->prompt = xrealloc(commandLine->prompt, strlen(prompt) + 1);
2608 strcpy(commandLine->prompt, prompt); 2609 strcpy(commandLine->prompt, prompt);
2609 // Move to the end of the history. 2610 // Move to the end of the history.
2610 moveCursorAbsolute(commandLine, 0, commandLine->content->lines.length, 0, 0); 2611 moveCursorAbsolute(commandLine, 0, commandLine->content->lines.length, 0, 0);
2611 2612
2612 // Run the main loop. 2613 // Run the main loop.
2613 currentBox = rootBox; 2614 currentBox = rootBox;
2614 editLine(currentBox->view, -1, -1, -1, -1); 2615 editLine(currentBox->view, -1, -1, -1, -1);
2615 2616
2616 puts("\n"); 2617 puts("\n");
2617 fflush(stdout); 2618 fflush(stdout);
2618} 2619}