summaryrefslogtreecommitdiff
path: root/editors/vi.c
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-05-07 17:37:43 +0000
committerEric Andersen <andersen@codepoet.org>2001-05-07 17:37:43 +0000
commit822c3837f95a355f90d25aaabeb2445bb5eb1bf0 (patch)
tree74a0aca850bc434a61e922d5efbd8b212603ffd1 /editors/vi.c
parent713b3987003ce61e3b1c9003f42b8490d666a850 (diff)
downloadbusybox-w32-822c3837f95a355f90d25aaabeb2445bb5eb1bf0.tar.gz
busybox-w32-822c3837f95a355f90d25aaabeb2445bb5eb1bf0.tar.bz2
busybox-w32-822c3837f95a355f90d25aaabeb2445bb5eb1bf0.zip
Another vi update from Sterling Huxley:
- All of the ESC sequences are now in variables. This should make re-targeting for other terminals easier. - The initial screen draw does not force out every single column. Should be faster. - The place_cursor() routine trys to be smarter about moving the cursor. This is optional based on BB_FEATURE_VI_OPTIMIZE_CURSOR. - The 't' and 'f' intra-line positioning commands were added. They can now be used as targets in 'c' and 'd' commands, i.e., dfx - delete from dot to next 'x' dtx - delete from dot to the char before next 'x' - show_status_line() uses a static int checksum to remember what is currently displayed on the screen and not re-draw the status line unless it has changed. - Some of the code in refresh() was moved out to format_line(). refresh() trys to send out the smallest segment containing the changed chars rather than the whole line. - Added "flash" to the :set command to specify if error indication should be by flashing the screen or ringing the bell. - Changed the rawmode() routine so that it turns off the NL -> CR NL translation. On output of a NL, the OS will not add a CR. - If vi was started as "view", with global read-only mode, and another file is opened, the file is opened read-only rather than read+write.
Diffstat (limited to 'editors/vi.c')
-rw-r--r--editors/vi.c572
1 files changed, 348 insertions, 224 deletions
diff --git a/editors/vi.c b/editors/vi.c
index 96fc96559..54f1d265c 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -19,13 +19,13 @@
19 */ 19 */
20 20
21char *vi_Version = 21char *vi_Version =
22 "$Id: vi.c,v 1.5 2001/04/26 15:56:47 andersen Exp $"; 22 "$Id: vi.c,v 1.6 2001/05/07 17:37:43 andersen Exp $";
23 23
24/* 24/*
25 * To compile for standalone use: 25 * To compile for standalone use:
26 * gcc -Wall -Os -s -DSTANDALONE -o vi vi.c 26 * gcc -Wall -Os -s -DSTANDALONE -o vi vi.c
27 * or 27 * or
28 * gcc -Wall -Os -s -DSTANDALONE -DCRASHME -o vi vi.c # include testing features 28 * gcc -Wall -Os -s -DSTANDALONE -DBB_FEATURE_VI_CRASHME -o vi vi.c # include testing features
29 * strip vi 29 * strip vi
30 */ 30 */
31 31
@@ -47,7 +47,7 @@ char *vi_Version =
47 47
48//---- Feature -------------- Bytes to immplement 48//---- Feature -------------- Bytes to immplement
49#ifdef STANDALONE 49#ifdef STANDALONE
50#define vi_main main 50#define vi_main main
51#define BB_FEATURE_VI_COLON // 4288 51#define BB_FEATURE_VI_COLON // 4288
52#define BB_FEATURE_VI_YANKMARK // 1408 52#define BB_FEATURE_VI_YANKMARK // 1408
53#define BB_FEATURE_VI_SEARCH // 1088 53#define BB_FEATURE_VI_SEARCH // 1088
@@ -62,7 +62,7 @@ char *vi_Version =
62// To stop testing, wait until all to text[] is deleted, or 62// To stop testing, wait until all to text[] is deleted, or
63// Ctrl-Z and kill -9 %1 63// Ctrl-Z and kill -9 %1
64// while in the editor Ctrl-T will toggle the crashme function on and off. 64// while in the editor Ctrl-T will toggle the crashme function on and off.
65//#define BB_FEATURE_VI_CRASHME // randomly pick commands to execute 65//#define BB_FEATURE_VI_CRASHME // randomly pick commands to execute
66#endif /* STANDALONE */ 66#endif /* STANDALONE */
67 67
68#ifndef STANDALONE 68#ifndef STANDALONE
@@ -144,7 +144,11 @@ static struct timeval tv; // use select() for small sleeps
144static char erase_char; // the users erase character 144static char erase_char; // the users erase character
145static int rows, columns; // the terminal screen is this size 145static int rows, columns; // the terminal screen is this size
146static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset 146static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset
147static char *SOs, *SOn; 147static char *SOs, *SOn; // terminal standout start/normal ESC sequence
148static char *bell; // terminal bell sequence
149static char *Ceol, *Ceos; // Clear-end-of-line and Clear-end-of-screen ESC sequence
150static char *CMrc; // Cursor motion arbitrary destination ESC sequence
151static char *CMup, *CMdown; // Cursor motion up and down ESC sequence
148static Byte *status_buffer; // mesages to the user 152static Byte *status_buffer; // mesages to the user
149static Byte last_input_char; // last char read from user 153static Byte last_input_char; // last char read from user
150static Byte last_forward_char; // last char searched for with 'f' 154static Byte last_forward_char; // last char searched for with 'f'
@@ -157,6 +161,9 @@ static Byte *dot; // where all the action takes place
157static int tabstop; 161static int tabstop;
158static struct termios term_orig, term_vi; // remember what the cooked mode was 162static struct termios term_orig, term_vi; // remember what the cooked mode was
159 163
164#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
165static int last_row; // where the cursor was last moved to
166#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
160#ifdef BB_FEATURE_VI_USE_SIGNALS 167#ifdef BB_FEATURE_VI_USE_SIGNALS
161static jmp_buf restart; // catch_sig() 168static jmp_buf restart; // catch_sig()
162#endif /* BB_FEATURE_VI_USE_SIGNALS */ 169#endif /* BB_FEATURE_VI_USE_SIGNALS */
@@ -172,7 +179,7 @@ static Byte *ioq, *ioq_start; // pointer to string for get_one_char to "read"
172static Byte *modifying_cmds; // cmds that modify text[] 179static Byte *modifying_cmds; // cmds that modify text[]
173#endif /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */ 180#endif /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */
174#ifdef BB_FEATURE_VI_READONLY 181#ifdef BB_FEATURE_VI_READONLY
175static int readonly; 182static int vi_readonly, readonly;
176#endif /* BB_FEATURE_VI_READONLY */ 183#endif /* BB_FEATURE_VI_READONLY */
177#ifdef BB_FEATURE_VI_SETOPTS 184#ifdef BB_FEATURE_VI_SETOPTS
178static int autoindent; 185static int autoindent;
@@ -234,7 +241,7 @@ static Byte get_one_char(void); // read 1 char from stdin
234static int file_size(Byte *); // what is the byte size of "fn" 241static int file_size(Byte *); // what is the byte size of "fn"
235static int file_insert(Byte *, Byte *, int); 242static int file_insert(Byte *, Byte *, int);
236static int file_write(Byte *, Byte *, Byte *); 243static int file_write(Byte *, Byte *, Byte *);
237static void place_cursor(int, int); 244static void place_cursor(int, int, int);
238static void screen_erase(); 245static void screen_erase();
239static void clear_to_eol(void); 246static void clear_to_eol(void);
240static void clear_to_eos(void); 247static void clear_to_eos(void);
@@ -249,6 +256,7 @@ static void psbs(char *, ...); // Print Status Buf in standout mode
249static void ni(Byte *); // display messages 256static void ni(Byte *); // display messages
250static void edit_status(void); // show file status on status line 257static void edit_status(void); // show file status on status line
251static void redraw(int); // force a full screen refresh 258static void redraw(int); // force a full screen refresh
259static void format_line(Byte*, Byte*, int);
252static void refresh(int); // update the terminal from screen[] 260static void refresh(int); // update the terminal from screen[]
253 261
254#ifdef BB_FEATURE_VI_SEARCH 262#ifdef BB_FEATURE_VI_SEARCH
@@ -261,9 +269,7 @@ static Byte *get_one_address(Byte *, int *); // get colon addr, if present
261static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present 269static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present
262static void colon(Byte *); // execute the "colon" mode cmds 270static void colon(Byte *); // execute the "colon" mode cmds
263#endif /* BB_FEATURE_VI_COLON */ 271#endif /* BB_FEATURE_VI_COLON */
264#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON)
265static Byte *get_input_line(Byte *); // get input line- use "status line" 272static Byte *get_input_line(Byte *); // get input line- use "status line"
266#endif /* BB_FEATURE_VI_SEARCH || BB_FEATURE_VI_COLON */
267#ifdef BB_FEATURE_VI_USE_SIGNALS 273#ifdef BB_FEATURE_VI_USE_SIGNALS
268static void winch_sig(int); // catch window size changes 274static void winch_sig(int); // catch window size changes
269static void suspend_sig(int); // catch ctrl-Z 275static void suspend_sig(int); // catch ctrl-Z
@@ -307,16 +313,23 @@ extern int vi_main(int argc, char **argv)
307 int i; 313 int i;
308#endif /* BB_FEATURE_VI_YANKMARK */ 314#endif /* BB_FEATURE_VI_YANKMARK */
309 315
316 CMrc= "\033[%d;%dH"; // Terminal Crusor motion ESC sequence
317 CMup= "\033[A"; // move cursor up one line, same col
318 CMdown="\n"; // move cursor down one line, same col
319 Ceol= "\033[0K"; // Clear from cursor to end of line
320 Ceos= "\033[0J"; // Clear from cursor to end of screen
310 SOs = "\033[7m"; // Terminal standout mode on 321 SOs = "\033[7m"; // Terminal standout mode on
311 SOn = "\033[0m"; // Terminal standout mode off 322 SOn = "\033[0m"; // Terminal standout mode off
323 bell= "\007"; // Terminal bell sequence
312#ifdef BB_FEATURE_VI_CRASHME 324#ifdef BB_FEATURE_VI_CRASHME
313 (void) srand((long) getpid()); 325 (void) srand((long) getpid());
314#endif /* BB_FEATURE_VI_CRASHME */ 326#endif /* BB_FEATURE_VI_CRASHME */
315 status_buffer = (Byte *) malloc(200); // hold messages to user 327 status_buffer = (Byte *) malloc(200); // hold messages to user
316#ifdef BB_FEATURE_VI_READONLY 328#ifdef BB_FEATURE_VI_READONLY
317 readonly = FALSE; 329 vi_readonly = readonly = FALSE;
318 if (strncmp(argv[0], "view", 4) == 0) { 330 if (strncmp(argv[0], "view", 4) == 0) {
319 readonly = TRUE; 331 readonly = TRUE;
332 vi_readonly = TRUE;
320 } 333 }
321#endif /* BB_FEATURE_VI_READONLY */ 334#endif /* BB_FEATURE_VI_READONLY */
322#ifdef BB_FEATURE_VI_SETOPTS 335#ifdef BB_FEATURE_VI_SETOPTS
@@ -348,10 +361,10 @@ extern int vi_main(int argc, char **argv)
348 readonly = TRUE; 361 readonly = TRUE;
349 break; 362 break;
350#endif /* BB_FEATURE_VI_READONLY */ 363#endif /* BB_FEATURE_VI_READONLY */
351 //case 'r': // recover flag- ignore- we don't use tmp file 364 //case 'r': // recover flag- ignore- we don't use tmp file
352 //case 'x': // encryption flag- ignore 365 //case 'x': // encryption flag- ignore
353 //case 'c': // execute command first 366 //case 'c': // execute command first
354 //case 'h': // help -- just use default 367 //case 'h': // help -- just use default
355 default: 368 default:
356 show_help(); 369 show_help();
357 break; 370 break;
@@ -397,12 +410,12 @@ static void edit_file(Byte * fn)
397 rawmode(); 410 rawmode();
398 rows = 24; 411 rows = 24;
399 columns = 80; 412 columns = 80;
413 ch= -1;
400#ifdef BB_FEATURE_VI_WIN_RESIZE 414#ifdef BB_FEATURE_VI_WIN_RESIZE
401 window_size_get(0); 415 window_size_get(0);
402#endif /* BB_FEATURE_VI_WIN_RESIZE */ 416#endif /* BB_FEATURE_VI_WIN_RESIZE */
403 new_screen(rows, columns); // get memory for virtual screen 417 new_screen(rows, columns); // get memory for virtual screen
404 418
405 ch= 0;
406 cnt = file_size(fn); // file size 419 cnt = file_size(fn); // file size
407 size = 2 * cnt; // 200% of file size 420 size = 2 * cnt; // 200% of file size
408 new_text(size); // get a text[] buffer 421 new_text(size); // get a text[] buffer
@@ -484,7 +497,7 @@ static void edit_file(Byte * fn)
484 ioq = ioq_start = last_modifying_cmd = 0; 497 ioq = ioq_start = last_modifying_cmd = 0;
485 adding2q = 0; 498 adding2q = 0;
486#endif /* BB_FEATURE_VI_DOT_CMD */ 499#endif /* BB_FEATURE_VI_DOT_CMD */
487 redraw(TRUE); 500 redraw(FALSE); // dont force every col re-draw
488 show_status_line(); 501 show_status_line();
489 502
490 //------This is the main Vi cmd handling loop ----------------------- 503 //------This is the main Vi cmd handling loop -----------------------
@@ -534,7 +547,7 @@ static void edit_file(Byte * fn)
534 } 547 }
535 //------------------------------------------------------------------- 548 //-------------------------------------------------------------------
536 549
537 place_cursor(rows, 0); // go to bottom of screen 550 place_cursor(rows, 0, FALSE); // go to bottom of screen
538 clear_to_eol(); // Erase to end of line 551 clear_to_eol(); // Erase to end of line
539 cookmode(); 552 cookmode();
540} 553}
@@ -649,7 +662,7 @@ static void crash_dummy()
649 i = (int) lrand48() % strlen(cmd); 662 i = (int) lrand48() % strlen(cmd);
650 cm = cmd[i]; 663 cm = cmd[i];
651 if (strchr(":\024", cm)) 664 if (strchr(":\024", cm))
652 goto cd0; // dont allow these commands 665 goto cd0; // dont allow colon or ctrl-T commands
653 readbuffer[rbi++] = cm; // put cmd into input buffer 666 readbuffer[rbi++] = cm; // put cmd into input buffer
654 667
655 // now we have the command- 668 // now we have the command-
@@ -725,11 +738,9 @@ static void crash_test()
725 738
726 if (strlen(msg) > 0) { 739 if (strlen(msg) > 0) {
727 alarm(0); 740 alarm(0);
728 sprintf(buf, "\n\n%d: \'%c\' ", totalcmds, last_input_char); 741 sprintf(buf, "\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
742 totalcmds, last_input_char, msg, SOs, SOn);
729 write(1, buf, strlen(buf)); 743 write(1, buf, strlen(buf));
730 write(1, msg, strlen(msg));
731 write(1, "\n\n\n", 3);
732 write(1, "\033[7m[Hit return to continue]\033[0m", 32);
733 while (read(0, d, 1) > 0) { 744 while (read(0, d, 1) > 0) {
734 if (d[0] == '\n' || d[0] == '\r') 745 if (d[0] == '\n' || d[0] == '\r')
735 break; 746 break;
@@ -803,50 +814,49 @@ static void do_cmd(Byte c)
803 } 814 }
804 815
805 switch (c) { 816 switch (c) {
806 //case 0x01: // soh 817 //case 0x01: // soh
807 //case 0x09: // ht 818 //case 0x09: // ht
808 //case 0x0b: // vt 819 //case 0x0b: // vt
809 //case 0x0e: // so 820 //case 0x0e: // so
810 //case 0x0f: // si 821 //case 0x0f: // si
811 //case 0x10: // dle 822 //case 0x10: // dle
812 //case 0x11: // dc1 823 //case 0x11: // dc1
813 //case 0x13: // dc3 824 //case 0x13: // dc3
814#ifdef BB_FEATURE_VI_CRASHME 825#ifdef BB_FEATURE_VI_CRASHME
815 case 0x14: // dc4 ctrl-T 826 case 0x14: // dc4 ctrl-T
816 crashme = (crashme == 0) ? 1 : 0; 827 crashme = (crashme == 0) ? 1 : 0;
817 break; 828 break;
818#endif /* BB_FEATURE_VI_CRASHME */ 829#endif /* BB_FEATURE_VI_CRASHME */
819 //case 0x16: // syn 830 //case 0x16: // syn
820 //case 0x17: // etb 831 //case 0x17: // etb
821 //case 0x18: // can 832 //case 0x18: // can
822 //case 0x1c: // fs 833 //case 0x1c: // fs
823 //case 0x1d: // gs 834 //case 0x1d: // gs
824 //case 0x1e: // rs 835 //case 0x1e: // rs
825 //case 0x1f: // us 836 //case 0x1f: // us
826 //case '!': // !- 837 //case '!': // !-
827 //case '#': // #- 838 //case '#': // #-
828 //case '&': // &- 839 //case '&': // &-
829 //case '(': // (- 840 //case '(': // (-
830 //case ')': // )- 841 //case ')': // )-
831 //case '*': // *- 842 //case '*': // *-
832 //case ',': // ,- 843 //case ',': // ,-
833 //case '=': // =- 844 //case '=': // =-
834 //case '@': // @- 845 //case '@': // @-
835 //case 'F': // F- 846 //case 'F': // F-
836 //case 'K': // K- 847 //case 'K': // K-
837 //case 'Q': // Q- 848 //case 'Q': // Q-
838 //case 'S': // S- 849 //case 'S': // S-
839 //case 'T': // T- 850 //case 'T': // T-
840 //case 'V': // V- 851 //case 'V': // V-
841 //case '[': // [- 852 //case '[': // [-
842 //case '\\': // \- 853 //case '\\': // \-
843 //case ']': // ]- 854 //case ']': // ]-
844 //case '_': // _- 855 //case '_': // _-
845 //case '`': // `- 856 //case '`': // `-
846 //case 'g': // g- 857 //case 'g': // g-
847 //case 't': // t-
848 //case 'u': // u- FIXME- there is no undo 858 //case 'u': // u- FIXME- there is no undo
849 //case 'v': // v- 859 //case 'v': // v-
850 default: // unrecognised command 860 default: // unrecognised command
851 buf[0] = c; 861 buf[0] = c;
852 buf[1] = '\0'; 862 buf[1] = '\0';
@@ -904,7 +914,7 @@ static void do_cmd(Byte c)
904 break; 914 break;
905 case 12: // ctrl-L force redraw whole screen 915 case 12: // ctrl-L force redraw whole screen
906 case 18: // ctrl-R force redraw 916 case 18: // ctrl-R force redraw
907 place_cursor(0, 0); // put cursor in correct place 917 place_cursor(0, 0, FALSE); // put cursor in correct place
908 clear_to_eos(); // tel terminal to erase display 918 clear_to_eos(); // tel terminal to erase display
909 (void) mysleep(10); 919 (void) mysleep(10);
910 screen_erase(); // erase the internal screen buffer 920 screen_erase(); // erase the internal screen buffer
@@ -924,7 +934,7 @@ static void do_cmd(Byte c)
924 case 25: // ctrl-Y scroll up one line 934 case 25: // ctrl-Y scroll up one line
925 dot_scroll(1, -1); 935 dot_scroll(1, -1);
926 break; 936 break;
927 case 0x1b: // esc 937 case 27: // esc
928 if (cmd_mode == 0) 938 if (cmd_mode == 0)
929 indicate_error(c); 939 indicate_error(c);
930 cmd_mode = 0; // stop insrting 940 cmd_mode = 0; // stop insrting
@@ -1053,8 +1063,9 @@ static void do_cmd(Byte c)
1053 //**** fall thru to ... 'i' 1063 //**** fall thru to ... 'i'
1054 case ';': // ;- look at rest of line for last forward char 1064 case ';': // ;- look at rest of line for last forward char
1055 if (cmdcnt-- > 1) { 1065 if (cmdcnt-- > 1) {
1056 do_cmd(c); 1066 do_cmd(';');
1057 } // repeat cnt 1067 } // repeat cnt
1068 if (last_forward_char == 0) break;
1058 q = dot + 1; 1069 q = dot + 1;
1059 while (q < end - 1 && *q != '\n' && *q != last_forward_char) { 1070 while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
1060 q++; 1071 q++;
@@ -1182,41 +1193,37 @@ static void do_cmd(Byte c)
1182 } 1193 }
1183 break; 1194 break;
1184 case ':': // :- the colon mode commands 1195 case ':': // :- the colon mode commands
1185#ifdef BB_FEATURE_VI_COLON
1186 p = get_input_line((Byte *) ":"); // get input line- use "status line" 1196 p = get_input_line((Byte *) ":"); // get input line- use "status line"
1197#ifdef BB_FEATURE_VI_COLON
1187 colon(p); // execute the command 1198 colon(p); // execute the command
1188#else /* BB_FEATURE_VI_COLON */ 1199#else /* BB_FEATURE_VI_COLON */
1189 *status_buffer = '\0'; // clear the status buffer 1200 if (*p == ':')
1190 place_cursor(rows - 1, 0); // go to Status line, bottom of screen 1201 p++; // move past the ':'
1191 clear_to_eol(); // clear the line 1202 cnt = strlen((char *) p);
1192 write(1, ":", 1); // write out the : prompt 1203 if (cnt <= 0)
1193 for (cnt = 0; cnt < 8; cnt++) { 1204 break;
1194 c1 = get_one_char(); 1205 if (strncasecmp((char *) p, "quit", cnt) == 0 ||
1195 if (c1 == '\n' || c1 == '\r' || c1 == 27) { 1206 strncasecmp((char *) p, "q!", cnt) == 0) { // delete lines
1196 break; 1207 if (file_modified == TRUE && p[1] != '!') {
1197 }
1198 buf[cnt] = c1;
1199 buf[cnt + 1] = '\0';
1200 write(1, buf + cnt, 1); // echo the char
1201 }
1202 cnt = strlen((char *) buf);
1203 if (strncasecmp((char *) buf, "quit", cnt) == 0 ||
1204 strncasecmp((char *) buf, "q!", cnt) == 0) { // delete lines
1205 if (file_modified == TRUE && buf[1] != '!') {
1206 psbs("No write since last change (:quit! overrides)"); 1208 psbs("No write since last change (:quit! overrides)");
1207 } else { 1209 } else {
1208 editing = 0; 1210 editing = 0;
1209 } 1211 }
1210 } else if (strncasecmp((char *) buf, "write", cnt) == 0 || 1212 } else if (strncasecmp((char *) p, "write", cnt) == 0 ||
1211 strncasecmp((char *) buf, "wq", cnt) == 0) { 1213 strncasecmp((char *) p, "wq", cnt) == 0) {
1212 cnt = file_write(cfn, text, end - 1); 1214 cnt = file_write(cfn, text, end - 1);
1213 file_modified = FALSE; 1215 file_modified = FALSE;
1214 psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt); 1216 psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt);
1215 if (buf[1] == 'q') { 1217 if (p[1] == 'q') {
1216 editing = 0; 1218 editing = 0;
1217 } 1219 }
1220 } else if (strncasecmp((char *) p, "file", cnt) == 0 ) {
1221 edit_status(); // show current file status
1222 } else if (sscanf((char *) p, "%d", &j) > 0) {
1223 dot = find_line(j); // go to line # j
1224 dot_skip_over_ws();
1218 } else { // unrecognised cmd 1225 } else { // unrecognised cmd
1219 ni((Byte *) buf); 1226 ni((Byte *) p);
1220 } 1227 }
1221#endif /* BB_FEATURE_VI_COLON */ 1228#endif /* BB_FEATURE_VI_COLON */
1222 break; 1229 break;
@@ -1287,10 +1294,10 @@ static void do_cmd(Byte c)
1287 end_cmd_q(); // stop adding to q 1294 end_cmd_q(); // stop adding to q
1288#endif /* BB_FEATURE_VI_DOT_CMD */ 1295#endif /* BB_FEATURE_VI_DOT_CMD */
1289 break; 1296 break;
1290 case 'G': // G- goto to a line number (default= E-O-F) 1297 case 'G': // G- goto to a line number (default= E-O-F)
1291 dot = end - 1; // assume E-O-F 1298 dot = end - 1; // assume E-O-F
1292 if (cmdcnt > 0) { 1299 if (cmdcnt > 0) {
1293 dot = find_line(cmdcnt); // what line is #cmdcnt 1300 dot = find_line(cmdcnt); // what line is #cmdcnt
1294 } 1301 }
1295 dot_skip_over_ws(); 1302 dot_skip_over_ws();
1296 break; 1303 break;
@@ -1338,13 +1345,13 @@ static void do_cmd(Byte c)
1338 dot_begin(); 1345 dot_begin();
1339 dot_skip_over_ws(); 1346 dot_skip_over_ws();
1340 break; 1347 break;
1341 case 'M': // M- goto middle line on screen 1348 case 'M': // M- goto middle line on screen
1342 dot = screenbegin; 1349 dot = screenbegin;
1343 for (cnt = 0; cnt < (rows-1) / 2; cnt++) 1350 for (cnt = 0; cnt < (rows-1) / 2; cnt++)
1344 dot = next_line(dot); 1351 dot = next_line(dot);
1345 break; 1352 break;
1346 case 'O': // O- open a empty line above 1353 case 'O': // O- open a empty line above
1347 // 0i\n\033-i 1354 // 0i\n ESC -i
1348 p = begin_line(dot); 1355 p = begin_line(dot);
1349 if (p[-1] == '\n') { 1356 if (p[-1] == '\n') {
1350 dot_prev(); 1357 dot_prev();
@@ -1353,7 +1360,7 @@ static void do_cmd(Byte c)
1353 dot = char_insert(dot, '\n'); 1360 dot = char_insert(dot, '\n');
1354 } else { 1361 } else {
1355 dot_begin(); // 0 1362 dot_begin(); // 0
1356 dot = char_insert(dot, '\n'); // i\n\033 1363 dot = char_insert(dot, '\n'); // i\n ESC
1357 dot_prev(); // - 1364 dot_prev(); // -
1358 } 1365 }
1359 goto dc_i; 1366 goto dc_i;
@@ -1390,6 +1397,7 @@ static void do_cmd(Byte c)
1390 } 1397 }
1391 if (file_modified == TRUE 1398 if (file_modified == TRUE
1392#ifdef BB_FEATURE_VI_READONLY 1399#ifdef BB_FEATURE_VI_READONLY
1400 && vi_readonly == FALSE
1393 && readonly == FALSE 1401 && readonly == FALSE
1394#endif /* BB_FEATURE_VI_READONLY */ 1402#endif /* BB_FEATURE_VI_READONLY */
1395 ) { 1403 ) {
@@ -1452,7 +1460,7 @@ static void do_cmd(Byte c)
1452 } 1460 }
1453 } 1461 }
1454 dot = yank_delete(p, q, 0, yf); // delete word 1462 dot = yank_delete(p, q, 0, yf); // delete word
1455 } else if (strchr("^0bBeE$", c1)) { 1463 } else if (strchr("^0bBeEft$", c1)) {
1456 // single line copy text into a register and delete 1464 // single line copy text into a register and delete
1457 dot = yank_delete(p, q, 0, yf); // delete word 1465 dot = yank_delete(p, q, 0, yf); // delete word
1458 } else if (strchr("cdykjHL%+-{}\r\n", c1)) { 1466 } else if (strchr("cdykjHL%+-{}\r\n", c1)) {
@@ -1514,6 +1522,13 @@ static void do_cmd(Byte c)
1514 } 1522 }
1515 end_cmd_q(); // stop adding to q 1523 end_cmd_q(); // stop adding to q
1516 break; 1524 break;
1525 case 't': // t- move to char prior to next x
1526 last_forward_char = get_one_char();
1527 do_cmd(';');
1528 if (*dot == last_forward_char)
1529 dot_left();
1530 last_forward_char= 0;
1531 break;
1517 case 'w': // w- forward a word 1532 case 'w': // w- forward a word
1518 if (cmdcnt-- > 1) { 1533 if (cmdcnt-- > 1) {
1519 do_cmd(c); 1534 do_cmd(c);
@@ -1699,19 +1714,19 @@ static void colon(Byte * buf)
1699 int useforce, forced; 1714 int useforce, forced;
1700 struct stat st_buf; 1715 struct stat st_buf;
1701 1716
1702 // :3154 // if (-e line 3154) goto it else stay put 1717 // :3154 // if (-e line 3154) goto it else stay put
1703 // :4,33w! foo // write a portion of buffer to file "foo" 1718 // :4,33w! foo // write a portion of buffer to file "foo"
1704 // :w // write all of buffer to current file 1719 // :w // write all of buffer to current file
1705 // :q // quit 1720 // :q // quit
1706 // :q! // quit- dont care about modified file 1721 // :q! // quit- dont care about modified file
1707 // :'a,'z!sort -u // filter block through sort 1722 // :'a,'z!sort -u // filter block through sort
1708 // :'f // goto mark "f" 1723 // :'f // goto mark "f"
1709 // :'fl // list literal the mark "f" line 1724 // :'fl // list literal the mark "f" line
1710 // :.r bar // read file "bar" into buffer before dot 1725 // :.r bar // read file "bar" into buffer before dot
1711 // :/123/,/abc/d // delete lines from "123" line to "abc" line 1726 // :/123/,/abc/d // delete lines from "123" line to "abc" line
1712 // :/xyz/ // goto the "xyz" line 1727 // :/xyz/ // goto the "xyz" line
1713 // :s/find/replace/ // substitute pattern "find" with "replace" 1728 // :s/find/replace/ // substitute pattern "find" with "replace"
1714 // :!<cmd> // run <cmd> then return 1729 // :!<cmd> // run <cmd> then return
1715 // 1730 //
1716 if (strlen((char *) buf) <= 0) 1731 if (strlen((char *) buf) <= 0)
1717 goto vc1; 1732 goto vc1;
@@ -1725,8 +1740,8 @@ static void colon(Byte * buf)
1725 r = end - 1; 1740 r = end - 1;
1726 li = count_lines(text, end - 1); 1741 li = count_lines(text, end - 1);
1727 fn = cfn; // default to current file 1742 fn = cfn; // default to current file
1728 memset(cmd, '\0', BUFSIZ); // clear cmd[] 1743 memset(cmd, '\0', BUFSIZ); // clear cmd[]
1729 memset(args, '\0', BUFSIZ); // clear args[] 1744 memset(args, '\0', BUFSIZ); // clear args[]
1730 1745
1731 // look for optional address(es) :. :1 :1,9 :'q,'a :% 1746 // look for optional address(es) :. :1 :1,9 :'q,'a :%
1732 buf = get_address(buf, &b, &e); 1747 buf = get_address(buf, &b, &e);
@@ -1745,7 +1760,7 @@ static void colon(Byte * buf)
1745 while (isblnk(*buf)) 1760 while (isblnk(*buf))
1746 buf++; 1761 buf++;
1747 strcpy((char *) args, (char *) buf); 1762 strcpy((char *) args, (char *) buf);
1748 if (last_char_is((char *)cmd,'!')) { 1763 if (last_char_is((char *)cmd, '!')) {
1749 useforce = TRUE; 1764 useforce = TRUE;
1750 cmd[strlen((char *) cmd) - 1] = '\0'; // get rid of ! 1765 cmd[strlen((char *) cmd) - 1] = '\0'; // get rid of !
1751 } 1766 }
@@ -1775,7 +1790,7 @@ static void colon(Byte * buf)
1775 } else if (strncmp((char *) cmd, "!", 1) == 0) { // run a cmd 1790 } else if (strncmp((char *) cmd, "!", 1) == 0) { // run a cmd
1776 // :!ls run the <cmd> 1791 // :!ls run the <cmd>
1777 (void) alarm(0); // wait for input- no alarms 1792 (void) alarm(0); // wait for input- no alarms
1778 place_cursor(rows - 1, 0); // go to Status line 1793 place_cursor(rows - 1, 0, FALSE); // go to Status line
1779 clear_to_eol(); // clear the line 1794 clear_to_eol(); // clear the line
1780 cookmode(); 1795 cookmode();
1781 system(orig_buf+1); // run the cmd 1796 system(orig_buf+1); // run the cmd
@@ -1870,14 +1885,14 @@ static void colon(Byte * buf)
1870#endif /* BB_FEATURE_VI_YANKMARK */ 1885#endif /* BB_FEATURE_VI_YANKMARK */
1871 // how many lines in text[]? 1886 // how many lines in text[]?
1872 li = count_lines(text, end - 1); 1887 li = count_lines(text, end - 1);
1873 psb("\"%s\"%s" 1888 psb("\"%s\"%s"
1874#ifdef BB_FEATURE_VI_READONLY 1889#ifdef BB_FEATURE_VI_READONLY
1875 "%s" 1890 "%s"
1876#endif /* BB_FEATURE_VI_READONLY */ 1891#endif /* BB_FEATURE_VI_READONLY */
1877 " %dL, %dC", cfn, 1892 " %dL, %dC", cfn,
1878 (sr < 0 ? " [New file]" : ""), 1893 (sr < 0 ? " [New file]" : ""),
1879#ifdef BB_FEATURE_VI_READONLY 1894#ifdef BB_FEATURE_VI_READONLY
1880 (readonly == TRUE ? " [Read only]" : ""), 1895 ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
1881#endif /* BB_FEATURE_VI_READONLY */ 1896#endif /* BB_FEATURE_VI_READONLY */
1882 li, ch); 1897 li, ch);
1883 } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this 1898 } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this
@@ -1896,7 +1911,7 @@ static void colon(Byte * buf)
1896 } 1911 }
1897 } else if (strncasecmp((char *) cmd, "features", i) == 0) { // what features are available 1912 } else if (strncasecmp((char *) cmd, "features", i) == 0) { // what features are available
1898 // print out values of all features 1913 // print out values of all features
1899 place_cursor(rows - 1, 0); // go to Status line, bottom of screen 1914 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
1900 clear_to_eol(); // clear the line 1915 clear_to_eol(); // clear the line
1901 cookmode(); 1916 cookmode();
1902 show_help(); 1917 show_help();
@@ -1907,7 +1922,7 @@ static void colon(Byte * buf)
1907 q = begin_line(dot); // assume .,. for the range 1922 q = begin_line(dot); // assume .,. for the range
1908 r = end_line(dot); 1923 r = end_line(dot);
1909 } 1924 }
1910 place_cursor(rows - 1, 0); // go to Status line, bottom of screen 1925 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
1911 clear_to_eol(); // clear the line 1926 clear_to_eol(); // clear the line
1912 write(1, "\r\n", 2); 1927 write(1, "\r\n", 2);
1913 for (; q <= r; q++) { 1928 for (; q <= r; q++) {
@@ -1973,13 +1988,13 @@ static void colon(Byte * buf)
1973 goto vc1; // nothing was inserted 1988 goto vc1; // nothing was inserted
1974 // how many lines in text[]? 1989 // how many lines in text[]?
1975 li = count_lines(q, q + ch - 1); 1990 li = count_lines(q, q + ch - 1);
1976 psb("\"%s\"" 1991 psb("\"%s\""
1977#ifdef BB_FEATURE_VI_READONLY 1992#ifdef BB_FEATURE_VI_READONLY
1978 "%s" 1993 "%s"
1979#endif /* BB_FEATURE_VI_READONLY */ 1994#endif /* BB_FEATURE_VI_READONLY */
1980 " %dL, %dC", fn, 1995 " %dL, %dC", fn,
1981#ifdef BB_FEATURE_VI_READONLY 1996#ifdef BB_FEATURE_VI_READONLY
1982 (readonly == TRUE ? " [Read only]" : ""), 1997 ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
1983#endif /* BB_FEATURE_VI_READONLY */ 1998#endif /* BB_FEATURE_VI_READONLY */
1984 li, ch); 1999 li, ch);
1985 if (ch > 0) { 2000 if (ch > 0) {
@@ -2001,13 +2016,16 @@ static void colon(Byte * buf)
2001 i = 0; // offset into args 2016 i = 0; // offset into args
2002 if (strlen((char *) args) == 0) { 2017 if (strlen((char *) args) == 0) {
2003 // print out values of all options 2018 // print out values of all options
2004 place_cursor(rows - 1, 0); // go to Status line, bottom of screen 2019 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
2005 clear_to_eol(); // clear the line 2020 clear_to_eol(); // clear the line
2006 printf("----------------------------------------\r\n"); 2021 printf("----------------------------------------\r\n");
2007#ifdef BB_FEATURE_VI_SETOPTS 2022#ifdef BB_FEATURE_VI_SETOPTS
2008 if (!autoindent) 2023 if (!autoindent)
2009 printf("no"); 2024 printf("no");
2010 printf("autoindent "); 2025 printf("autoindent ");
2026 if (!err_method)
2027 printf("no");
2028 printf("flash ");
2011 if (!ignorecase) 2029 if (!ignorecase)
2012 printf("no"); 2030 printf("no");
2013 printf("ignorecase "); 2031 printf("ignorecase ");
@@ -2026,6 +2044,10 @@ static void colon(Byte * buf)
2026 strncasecmp((char *) args + i, "ai", 2) == 0) { 2044 strncasecmp((char *) args + i, "ai", 2) == 0) {
2027 autoindent = (i == 2) ? 0 : 1; 2045 autoindent = (i == 2) ? 0 : 1;
2028 } 2046 }
2047 if (strncasecmp((char *) args + i, "flash", 5) == 0 ||
2048 strncasecmp((char *) args + i, "fl", 2) == 0) {
2049 err_method = (i == 2) ? 0 : 1;
2050 }
2029 if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 || 2051 if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 ||
2030 strncasecmp((char *) args + i, "ic", 2) == 0) { 2052 strncasecmp((char *) args + i, "ic", 2) == 0) {
2031 ignorecase = (i == 2) ? 0 : 1; 2053 ignorecase = (i == 2) ? 0 : 1;
@@ -2096,7 +2118,7 @@ static void colon(Byte * buf)
2096 fn = args; 2118 fn = args;
2097 } 2119 }
2098#ifdef BB_FEATURE_VI_READONLY 2120#ifdef BB_FEATURE_VI_READONLY
2099 if (readonly == TRUE && useforce == FALSE) { 2121 if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) {
2100 psbs("\"%s\" File is read only", fn); 2122 psbs("\"%s\" File is read only", fn);
2101 goto vc3; 2123 goto vc3;
2102 } 2124 }
@@ -2452,10 +2474,18 @@ static Byte *bound_dot(Byte * p) // make sure text[0] <= P < "end"
2452 2474
2453static Byte *new_screen(int ro, int co) 2475static Byte *new_screen(int ro, int co)
2454{ 2476{
2477 int li;
2478
2455 if (screen != 0) 2479 if (screen != 0)
2456 free(screen); 2480 free(screen);
2457 screensize = ro * co + 8; 2481 screensize = ro * co + 8;
2458 screen = (Byte *) malloc(screensize); 2482 screen = (Byte *) malloc(screensize);
2483 // initialize the new screen. assume this will be a empty file.
2484 screen_erase();
2485 // non-existant text[] lines start with a tilde (~).
2486 for (li = 1; li < ro - 1; li++) {
2487 screen[(li * co) + 0] = '~';
2488 }
2459 return (screen); 2489 return (screen);
2460} 2490}
2461 2491
@@ -2469,9 +2499,9 @@ static Byte *new_text(int size)
2469 } 2499 }
2470 text = (Byte *) malloc(size + 8); 2500 text = (Byte *) malloc(size + 8);
2471 memset(text, '\0', size); // clear new text[] 2501 memset(text, '\0', size); // clear new text[]
2472 //text += 4; // leave some room for "oops" 2502 //text += 4; // leave some room for "oops"
2473 textend = text + size - 1; 2503 textend = text + size - 1;
2474 //textend -= 4; // leave some root for "oops" 2504 //textend -= 4; // leave some root for "oops"
2475 return (text); 2505 return (text);
2476} 2506}
2477 2507
@@ -2596,7 +2626,7 @@ static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
2596 cmd_mode = 0; 2626 cmd_mode = 0;
2597 cmdcnt = 0; 2627 cmdcnt = 0;
2598 end_cmd_q(); // stop adding to q 2628 end_cmd_q(); // stop adding to q
2599 *status_buffer = '\0'; // clear the status buffer 2629 strcpy((char *) status_buffer, " "); // clear the status buffer
2600 if (p[-1] != '\n') { 2630 if (p[-1] != '\n') {
2601 p--; 2631 p--;
2602 } 2632 }
@@ -2667,7 +2697,7 @@ static Byte find_range(Byte ** start, Byte ** stop, Byte c)
2667 q = next_line(q); 2697 q = next_line(q);
2668 } 2698 }
2669 q = end_line(q); 2699 q = end_line(q);
2670 } else if (strchr("^%$0bBeE", c)) { 2700 } else if (strchr("^%$0bBeEft", c)) {
2671 // These cmds operate on char positions 2701 // These cmds operate on char positions
2672 do_cmd(c); // execute movement cmd 2702 do_cmd(c); // execute movement cmd
2673 q = dot; 2703 q = dot;
@@ -2931,6 +2961,7 @@ static void show_help(void)
2931 printf("\tNamed buffers with \"x\n"); 2961 printf("\tNamed buffers with \"x\n");
2932#endif /* BB_FEATURE_VI_YANKMARK */ 2962#endif /* BB_FEATURE_VI_YANKMARK */
2933#ifdef BB_FEATURE_VI_READONLY 2963#ifdef BB_FEATURE_VI_READONLY
2964 printf("\tReadonly if vi is called as \"view\"\n");
2934 printf("\tReadonly with -R command line arg\n"); 2965 printf("\tReadonly with -R command line arg\n");
2935#endif /* BB_FEATURE_VI_READONLY */ 2966#endif /* BB_FEATURE_VI_READONLY */
2936#ifdef BB_FEATURE_VI_SET 2967#ifdef BB_FEATURE_VI_SET
@@ -3111,6 +3142,7 @@ static void rawmode(void)
3111 term_vi = term_orig; 3142 term_vi = term_orig;
3112 term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's 3143 term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's
3113 term_vi.c_iflag &= (~IXON & ~ICRNL); 3144 term_vi.c_iflag &= (~IXON & ~ICRNL);
3145 term_vi.c_oflag &= (~ONLCR);
3114 term_vi.c_cc[VMIN] = 1; 3146 term_vi.c_cc[VMIN] = 1;
3115 term_vi.c_cc[VTIME] = 0; 3147 term_vi.c_cc[VTIME] = 0;
3116 erase_char = term_vi.c_cc[VERASE]; 3148 erase_char = term_vi.c_cc[VERASE];
@@ -3172,7 +3204,7 @@ static void cont_sig(int sig)
3172//----- Come here when we get a Suspend signal ------------------- 3204//----- Come here when we get a Suspend signal -------------------
3173static void suspend_sig(int sig) 3205static void suspend_sig(int sig)
3174{ 3206{
3175 place_cursor(rows, 0); // go to bottom of screen 3207 place_cursor(rows - 1, 0, FALSE); // go to bottom of screen
3176 clear_to_eol(); // Erase to end of line 3208 clear_to_eol(); // Erase to end of line
3177 cookmode(); // terminal to "cooked" 3209 cookmode(); // terminal to "cooked"
3178 3210
@@ -3181,7 +3213,7 @@ static void suspend_sig(int sig)
3181 kill(getpid(), SIGTSTP); 3213 kill(getpid(), SIGTSTP);
3182} 3214}
3183 3215
3184//----- Come here when we get a signal -------------------- 3216//----- Come here when we get a signal ---------------------------
3185static void catch_sig(int sig) 3217static void catch_sig(int sig)
3186{ 3218{
3187 signal(SIGHUP, catch_sig); 3219 signal(SIGHUP, catch_sig);
@@ -3382,7 +3414,6 @@ static Byte get_one_char()
3382 return (c); // return the char, where ever it came from 3414 return (c); // return the char, where ever it came from
3383} 3415}
3384 3416
3385#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON)
3386static Byte *get_input_line(Byte * prompt) // get input line- use "status line" 3417static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
3387{ 3418{
3388 Byte buf[BUFSIZ]; 3419 Byte buf[BUFSIZ];
@@ -3392,7 +3423,7 @@ static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
3392 3423
3393 strcpy((char *) buf, (char *) prompt); 3424 strcpy((char *) buf, (char *) prompt);
3394 *status_buffer = '\0'; // clear the status buffer 3425 *status_buffer = '\0'; // clear the status buffer
3395 place_cursor(rows - 1, 0); // go to Status line, bottom of screen 3426 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
3396 clear_to_eol(); // clear the line 3427 clear_to_eol(); // clear the line
3397 write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt 3428 write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt
3398 3429
@@ -3421,7 +3452,6 @@ static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
3421 obufp = (Byte *) strdup((char *) buf); 3452 obufp = (Byte *) strdup((char *) buf);
3422 return (obufp); 3453 return (obufp);
3423} 3454}
3424#endif /* BB_FEATURE_VI_SEARCH || BB_FEATURE_VI_COLON */
3425 3455
3426static int file_size(Byte * fn) // what is the byte size of "fn" 3456static int file_size(Byte * fn) // what is the byte size of "fn"
3427{ 3457{
@@ -3465,9 +3495,15 @@ static int file_insert(Byte * fn, Byte * p, int size)
3465 } 3495 }
3466 3496
3467 // see if we can open the file 3497 // see if we can open the file
3498#ifdef BB_FEATURE_VI_READONLY
3499 if (vi_readonly == TRUE) goto fi1; // do not try write-mode
3500#endif
3468 fd = open((char *) fn, O_RDWR); // assume read & write 3501 fd = open((char *) fn, O_RDWR); // assume read & write
3469 if (fd < 0) { 3502 if (fd < 0) {
3470 // could not open for writing- maybe file is read only 3503 // could not open for writing- maybe file is read only
3504#ifdef BB_FEATURE_VI_READONLY
3505 fi1:
3506#endif
3471 fd = open((char *) fn, O_RDONLY); // try read-only 3507 fd = open((char *) fn, O_RDONLY); // try read-only
3472 if (fd < 0) { 3508 if (fd < 0) {
3473 psbs("\"%s\" %s", fn, "could not open file"); 3509 psbs("\"%s\" %s", fn, "could not open file");
@@ -3529,51 +3565,96 @@ static int file_write(Byte * fn, Byte * first, Byte * last)
3529// 1,0 ... 1,79 3565// 1,0 ... 1,79
3530// . ... . 3566// . ... .
3531// . ... . 3567// . ... .
3532// 22,0 ... 22,79 3568// 22,0 ... 22,79
3533// 23,0 ... 23,79 status line 3569// 23,0 ... 23,79 status line
3534// 3570//
3535 3571
3536//----- Move the cursor to row x col (count from 0, not 1) ------- 3572//----- Move the cursor to row x col (count from 0, not 1) -------
3537static void place_cursor(int row, int col) 3573static void place_cursor(int row, int col, int opti)
3538{ 3574{
3539 Byte buf[30]; 3575 char cm1[BUFSIZ];
3576 char *cm;
3540 int l; 3577 int l;
3541 3578#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
3542 if (row < 0) 3579 char cm2[BUFSIZ];
3543 row = 0; 3580 Byte *screenp;
3544 if (row >= rows) 3581 // char cm3[BUFSIZ];
3545 row = rows - 1; 3582 int Rrow= last_row;
3546 if (col < 0) 3583#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3547 col = 0; 3584
3548 if (col >= columns) 3585 memset(cm1, '\0', BUFSIZ - 1); // clear the buffer
3549 col = columns - 1; 3586
3550 sprintf((char *) buf, "%c[%d;%dH", 0x1b, row + 1, col + 1); 3587 if (row < 0) row = 0;
3551 l = strlen((char *) buf); 3588 if (row >= rows) row = rows - 1;
3552 write(1, buf, l); 3589 if (col < 0) col = 0;
3590 if (col >= columns) col = columns - 1;
3591
3592 //----- 1. Try the standard terminal ESC sequence
3593 sprintf((char *) cm1, CMrc, row + 1, col + 1);
3594 cm= cm1;
3595 if (opti == FALSE) goto pc0;
3596
3597#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
3598 //----- find the minimum # of chars to move cursor -------------
3599 //----- 2. Try moving with discreet chars (Newline, [back]space, ...)
3600 memset(cm2, '\0', BUFSIZ - 1); // clear the buffer
3601
3602 // move to the correct row
3603 while (row < Rrow) {
3604 // the cursor has to move up
3605 strcat(cm2, CMup);
3606 Rrow--;
3607 }
3608 while (row > Rrow) {
3609 // the cursor has to move down
3610 strcat(cm2, CMdown);
3611 Rrow++;
3612 }
3613
3614 // now move to the correct column
3615 strcat(cm2, "\r"); // start at col 0
3616 // just send out orignal source char to get to correct place
3617 screenp = &screen[row * columns]; // start of screen line
3618 strncat(cm2, screenp, col);
3619
3620 //----- 3. Try some other way of moving cursor
3621 //---------------------------------------------
3622
3623 // pick the shortest cursor motion to send out
3624 cm= cm1;
3625 if (strlen(cm2) < strlen(cm)) {
3626 cm= cm2;
3627 } /* else if (strlen(cm3) < strlen(cm)) {
3628 cm= cm3;
3629 } */
3630#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3631 pc0:
3632 l= strlen(cm);
3633 if (l) write(1, cm, l); // move the cursor
3553} 3634}
3554 3635
3555//----- Erase from cursor to end of line ----------------------- 3636//----- Erase from cursor to end of line -----------------------
3556static void clear_to_eol() 3637static void clear_to_eol()
3557{ 3638{
3558 write(1, "\033[0K", 4); // Erase from cursor to end of line 3639 write(1, Ceol, strlen(Ceol)); // Erase from cursor to end of line
3559} 3640}
3560 3641
3561//----- Erase from cursor to end of screen ----------------------- 3642//----- Erase from cursor to end of screen -----------------------
3562static void clear_to_eos() 3643static void clear_to_eos()
3563{ 3644{
3564 write(1, "\033[0J", 4); // Erase from cursor to end of screen 3645 write(1, Ceos, strlen(Ceos)); // Erase from cursor to end of screen
3565} 3646}
3566 3647
3567//----- Start standout mode ------------------------------------ 3648//----- Start standout mode ------------------------------------
3568static void standout_start() // send "start reverse video" sequence 3649static void standout_start() // send "start reverse video" sequence
3569{ 3650{
3570 write(1, "\033[7m", 4); // Start reverse video mode 3651 write(1, SOs, strlen(SOs)); // Start reverse video mode
3571} 3652}
3572 3653
3573//----- End standout mode -------------------------------------- 3654//----- End standout mode --------------------------------------
3574static void standout_end() // send "end reverse video" sequence 3655static void standout_end() // send "end reverse video" sequence
3575{ 3656{
3576 write(1, "\033[0m", 4); // End reverse video mode 3657 write(1, SOn, strlen(SOn)); // End reverse video mode
3577} 3658}
3578 3659
3579//----- Flash the screen -------------------------------------- 3660//----- Flash the screen --------------------------------------
@@ -3588,7 +3669,7 @@ static void flash(int h)
3588 3669
3589static void beep() 3670static void beep()
3590{ 3671{
3591 write(1, "\007", 1); // send out a bell character 3672 write(1, bell, strlen(bell)); // send out a bell character
3592} 3673}
3593 3674
3594static void indicate_error(char c) 3675static void indicate_error(char c)
@@ -3608,25 +3689,25 @@ static void indicate_error(char c)
3608//----- Erase the Screen[] memory ------------------------------ 3689//----- Erase the Screen[] memory ------------------------------
3609static void screen_erase() 3690static void screen_erase()
3610{ 3691{
3611 int i; 3692 memset(screen, ' ', screensize); // clear new screen
3612
3613 for (i = 0; i < screensize; i++) {
3614 screen[i] = '\0';
3615 }
3616} 3693}
3617 3694
3618//----- Draw the status line at bottom of the screen ------------- 3695//----- Draw the status line at bottom of the screen -------------
3619static void show_status_line(void) 3696static void show_status_line(void)
3620{ 3697{
3621 int cnt; 3698 static int last_cksum;
3699 int l, cnt, cksum;
3622 3700
3623 cnt = strlen((char *) status_buffer); 3701 cnt = strlen((char *) status_buffer);
3624 place_cursor(rows - 1, 0); // put cursor on status line 3702 for (cksum= l= 0; l < cnt; l++) { cksum += (int)(status_buffer[l]); }
3625 if (cnt > 0) { 3703 // don't write the status line unless it changes
3704 if (cnt > 0 && last_cksum != cksum) {
3705 last_cksum= cksum; // remember if we have seen this line
3706 place_cursor(rows - 1, 0, FALSE); // put cursor on status line
3626 write(1, status_buffer, cnt); 3707 write(1, status_buffer, cnt);
3708 clear_to_eol();
3709 place_cursor(crow, ccol, FALSE); // put cursor back in correct place
3627 } 3710 }
3628 clear_to_eol();
3629 place_cursor(crow, ccol); // put cursor back in correct place
3630} 3711}
3631 3712
3632//----- format the status buffer, the bottom line of screen ------ 3713//----- format the status buffer, the bottom line of screen ------
@@ -3636,10 +3717,10 @@ static void psbs(char *format, ...)
3636 va_list args; 3717 va_list args;
3637 3718
3638 va_start(args, format); 3719 va_start(args, format);
3639 strcpy((char *) status_buffer, "\033[7m"); // Terminal standout mode on 3720 strcpy((char *) status_buffer, SOs); // Terminal standout mode on
3640 vsprintf((char *) status_buffer + strlen((char *) status_buffer), format, 3721 vsprintf((char *) status_buffer + strlen((char *) status_buffer), format,
3641 args); 3722 args);
3642 strcat((char *) status_buffer, "\033[0m"); // Terminal standout mode off 3723 strcat((char *) status_buffer, SOn); // Terminal standout mode off
3643 va_end(args); 3724 va_end(args);
3644 3725
3645 return; 3726 return;
@@ -3686,7 +3767,7 @@ static void edit_status(void) // show file status on status line
3686 "%s line %d of %d --%d%%--", 3767 "%s line %d of %d --%d%%--",
3687 (cfn != 0 ? (char *) cfn : "No file"), 3768 (cfn != 0 ? (char *) cfn : "No file"),
3688#ifdef BB_FEATURE_VI_READONLY 3769#ifdef BB_FEATURE_VI_READONLY
3689 (readonly == TRUE ? " [Read only]" : ""), 3770 ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
3690#endif /* BB_FEATURE_VI_READONLY */ 3771#endif /* BB_FEATURE_VI_READONLY */
3691 (file_modified == TRUE ? " [modified]" : ""), 3772 (file_modified == TRUE ? " [modified]" : ""),
3692 cur, tot, percent); 3773 cur, tot, percent);
@@ -3695,12 +3776,50 @@ static void edit_status(void) // show file status on status line
3695//----- Force refresh of all Lines ----------------------------- 3776//----- Force refresh of all Lines -----------------------------
3696static void redraw(int full_screen) 3777static void redraw(int full_screen)
3697{ 3778{
3698 place_cursor(0, 0); // put cursor in correct place 3779 place_cursor(0, 0, FALSE); // put cursor in correct place
3699 clear_to_eos(); // tel terminal to erase display 3780 clear_to_eos(); // tel terminal to erase display
3700 screen_erase(); // erase the internal screen buffer 3781 screen_erase(); // erase the internal screen buffer
3701 refresh(full_screen); // this will redraw the entire display 3782 refresh(full_screen); // this will redraw the entire display
3702} 3783}
3703 3784
3785//----- Format a text[] line into a buffer ---------------------
3786static void format_line(Byte *dest, Byte *src, int li)
3787{
3788 int co;
3789 Byte c;
3790
3791 for (co= 0; co < MAX_SCR_COLS; co++) {
3792 c= ' '; // assume blank
3793 if (li > 0 && co == 0) {
3794 c = '~'; // not first line, assume Tilde
3795 }
3796 // are there chars in text[] and have we gone past the end
3797 if (text < end && src < end) {
3798 c = *src++;
3799 }
3800 if (c == '\n')
3801 break;
3802 if (c < ' ' || c > '~') {
3803 if (c == '\t') {
3804 c = ' ';
3805 // co % 8 != 7
3806 for (; (co % tabstop) != (tabstop - 1); co++) {
3807 dest[co] = c;
3808 }
3809 } else {
3810 dest[co++] = '^';
3811 c |= '@'; // make it visible
3812 c &= 0x7f; // get rid of hi bit
3813 }
3814 }
3815 // the co++ is done here so that the column will
3816 // not be overwritten when we blank-out the rest of line
3817 dest[co] = c;
3818 if (src >= end)
3819 break;
3820 }
3821}
3822
3704//----- Refresh the changed screen lines ----------------------- 3823//----- Refresh the changed screen lines -----------------------
3705// Copy the source line from text[] into the buffer and note 3824// Copy the source line from text[] into the buffer and note
3706// if the current screenline is different from the new buffer. 3825// if the current screenline is different from the new buffer.
@@ -3709,97 +3828,102 @@ static void redraw(int full_screen)
3709static void refresh(int full_screen) 3828static void refresh(int full_screen)
3710{ 3829{
3711 static int old_offset; 3830 static int old_offset;
3712 int li, co, changed; 3831 int li, changed;
3713 Byte c, buf[MAX_SCR_COLS]; 3832 Byte buf[MAX_SCR_COLS];
3714 Byte *tp, *sp; // pointer into text[] and screen[] 3833 Byte *tp, *sp; // pointer into text[] and screen[]
3834#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
3835 int last_li= -2; // last line that changed- for optimizing cursor movement
3836#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3715 3837
3716#ifdef BB_FEATURE_VI_WIN_RESIZE 3838#ifdef BB_FEATURE_VI_WIN_RESIZE
3717 window_size_get(0); 3839 window_size_get(0);
3718#endif /* BB_FEATURE_VI_WIN_RESIZE */ 3840#endif /* BB_FEATURE_VI_WIN_RESIZE */
3719 sync_cursor(dot, &crow, &ccol); 3841 sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot")
3720 tp = screenbegin; // index into text[] of top line 3842 tp = screenbegin; // index into text[] of top line
3843
3721 // compare text[] to screen[] and mark screen[] lines that need updating 3844 // compare text[] to screen[] and mark screen[] lines that need updating
3722 for (li = 0; li < rows - 1; li++) { 3845 for (li = 0; li < rows - 1; li++) {
3723 // format current text line into buf with "columns" wide 3846 int cs, ce; // column start & end
3724 for (co = 0; co < columns + offset;) { 3847 memset(buf, ' ', MAX_SCR_COLS); // blank-out the buffer
3725 c = ' '; // assume blank 3848 buf[MAX_SCR_COLS-1] = 0; // NULL terminate the buffer
3726 if (li > 0 && co == 0) { 3849 // format current text line into buf
3727 c = '~'; // not first line, assume Tilde 3850 format_line(buf, tp, li);
3728 } 3851
3729 // are there chars in text[] 3852 // skip to the end of the current text[] line
3730 // and have we gone past the end 3853 while (tp < end && *tp++ != '\n') /*no-op*/ ;
3731 if (text < end && tp < end) { 3854
3732 c = *tp++; 3855 // see if there are any changes between vitual screen and buf
3733 } 3856 changed = FALSE; // assume no change
3734 if (c == '\n') 3857 cs= 0;
3858 ce= columns-1;
3859 sp = &screen[li * columns]; // start of screen line
3860 if (full_screen == TRUE) {
3861 // force re-draw of every single column from 0 - columns-1
3862 goto re0;
3863 }
3864 // compare newly formatted buffer with virtual screen
3865 // look forward for first difference between buf and screen
3866 for ( ; cs <= ce; cs++) {
3867 if (buf[cs + offset] != sp[cs]) {
3868 changed = TRUE; // mark for redraw
3735 break; 3869 break;
3736 if (c < ' ' || c > '~') {
3737 if (c == '\t') {
3738 c = ' ';
3739 // co % 8 != 7
3740 for (; (co % tabstop) != (tabstop - 1); co++) {
3741 buf[co] = c;
3742 }
3743 } else {
3744 buf[co++] = '^';
3745 c |= '@'; // make it visible
3746 c &= 0x7f; // get rid of hi bit
3747 }
3748 } 3870 }
3749 // the co++ is done here so that the column will
3750 // not be overwritten when we blank-out the rest of line
3751 buf[co++] = c;
3752 if (tp >= end)
3753 break;
3754 }
3755 if (co >= columns + offset) {
3756 // skip to the end of the current text[] line
3757 while (tp < end && *tp++ != '\n');
3758 } 3871 }
3759 // try to keep the cursor near it's current position
3760 // remember how many chars in this row- where the cursor sits
3761 // blank out the rest of the buffer
3762 while (co < MAX_SCR_COLS - 1) {
3763 buf[co++] = ' ';
3764 }
3765 buf[co++] = 0; // NULL terminate the buffer
3766 3872
3767 // if necessary, update virtual screen[] and terminal from buf[] 3873 // look backward for last difference between buf and screen
3768 changed = FALSE; // assume no change 3874 for ( ; ce >= cs; ce--) {
3769 sp = &screen[li * columns]; // start of screen line 3875 if (buf[ce + offset] != sp[ce]) {
3770 for (co = 0; co < columns; co++) {
3771 if (sp[co] != buf[co + offset]) {
3772 sp[co] = buf[co + offset];
3773 changed = TRUE; // mark for redraw 3876 changed = TRUE; // mark for redraw
3877 break;
3774 } 3878 }
3775 } 3879 }
3880 // now, cs is index of first diff, and ce is index of last diff
3881
3776 // if horz offset has changed, force a redraw 3882 // if horz offset has changed, force a redraw
3777 if (offset != old_offset) 3883 if (offset != old_offset) {
3884 re0:
3778 changed = TRUE; 3885 changed = TRUE;
3886 }
3779 3887
3780 // write all marked screen lines out to terminal 3888 // make a sanity check of columns indexes
3889 if (cs < 0) cs= 0;
3890 if (ce > columns-1) ce= columns-1;
3891 if (cs > ce) { cs= 0; ce= columns-1; }
3892 // is there a change between vitual screen and buf
3781 if (changed == TRUE) { 3893 if (changed == TRUE) {
3782 place_cursor(li, 0); // put cursor in correct place 3894 // copy changed part of buffer to virtual screen
3783 clear_to_eol(); // Erase to end of line 3895 memmove(sp+cs, buf+(cs+offset), ce-cs+1);
3784 if (full_screen == FALSE) { 3896
3785 // don't redraw every column on terminal 3897 // move cursor to column of first change
3786 // look backwards for last non-blank 3898 if (offset != old_offset) {
3787 for (co = columns + offset; co >= 0; co--) { 3899 // opti_cur_move is still too stupid
3788 // break; 3900 // to handle offsets correctly
3789 if (buf[co] != ' ') 3901 place_cursor(li, cs, FALSE);
3790 break;
3791 }
3792 co++;
3793 } else { 3902 } else {
3794 // redraw every column on terminal 3903#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
3795 co = columns; 3904 // if this just the next line
3905 // try to optimize cursor movement
3906 // otherwise, use standard ESC sequence
3907 place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE);
3908 last_li= li;
3909#else /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3910 place_cursor(li, cs, FALSE); // use standard ESC sequence
3911#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3796 } 3912 }
3913
3797 // write line out to terminal 3914 // write line out to terminal
3798 write(1, buf + offset, co); 3915 write(1, sp+cs, ce-cs+1);
3916#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
3917 last_row = li;
3918#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3799 } 3919 }
3800 } 3920 }
3801 3921
3802 place_cursor(crow, ccol); 3922 place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE);
3923#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
3924 last_row = crow;
3925#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
3926
3803 if (offset != old_offset) 3927 if (offset != old_offset)
3804 old_offset = offset; 3928 old_offset = offset;
3805} 3929}