mirror of
https://github.com/sheumann/hush.git
synced 2024-12-27 01:32:08 +00:00
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.
This commit is contained in:
parent
713b398700
commit
822c3837f9
446
editors/vi.c
446
editors/vi.c
@ -19,13 +19,13 @@
|
||||
*/
|
||||
|
||||
char *vi_Version =
|
||||
"$Id: vi.c,v 1.5 2001/04/26 15:56:47 andersen Exp $";
|
||||
"$Id: vi.c,v 1.6 2001/05/07 17:37:43 andersen Exp $";
|
||||
|
||||
/*
|
||||
* To compile for standalone use:
|
||||
* gcc -Wall -Os -s -DSTANDALONE -o vi vi.c
|
||||
* or
|
||||
* gcc -Wall -Os -s -DSTANDALONE -DCRASHME -o vi vi.c # include testing features
|
||||
* gcc -Wall -Os -s -DSTANDALONE -DBB_FEATURE_VI_CRASHME -o vi vi.c # include testing features
|
||||
* strip vi
|
||||
*/
|
||||
|
||||
@ -144,7 +144,11 @@ static struct timeval tv; // use select() for small sleeps
|
||||
static char erase_char; // the users erase character
|
||||
static int rows, columns; // the terminal screen is this size
|
||||
static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset
|
||||
static char *SOs, *SOn;
|
||||
static char *SOs, *SOn; // terminal standout start/normal ESC sequence
|
||||
static char *bell; // terminal bell sequence
|
||||
static char *Ceol, *Ceos; // Clear-end-of-line and Clear-end-of-screen ESC sequence
|
||||
static char *CMrc; // Cursor motion arbitrary destination ESC sequence
|
||||
static char *CMup, *CMdown; // Cursor motion up and down ESC sequence
|
||||
static Byte *status_buffer; // mesages to the user
|
||||
static Byte last_input_char; // last char read from user
|
||||
static Byte last_forward_char; // last char searched for with 'f'
|
||||
@ -157,6 +161,9 @@ static Byte *dot; // where all the action takes place
|
||||
static int tabstop;
|
||||
static struct termios term_orig, term_vi; // remember what the cooked mode was
|
||||
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
static int last_row; // where the cursor was last moved to
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
#ifdef BB_FEATURE_VI_USE_SIGNALS
|
||||
static jmp_buf restart; // catch_sig()
|
||||
#endif /* BB_FEATURE_VI_USE_SIGNALS */
|
||||
@ -172,7 +179,7 @@ static Byte *ioq, *ioq_start; // pointer to string for get_one_char to "read"
|
||||
static Byte *modifying_cmds; // cmds that modify text[]
|
||||
#endif /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
static int readonly;
|
||||
static int vi_readonly, readonly;
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
#ifdef BB_FEATURE_VI_SETOPTS
|
||||
static int autoindent;
|
||||
@ -234,7 +241,7 @@ static Byte get_one_char(void); // read 1 char from stdin
|
||||
static int file_size(Byte *); // what is the byte size of "fn"
|
||||
static int file_insert(Byte *, Byte *, int);
|
||||
static int file_write(Byte *, Byte *, Byte *);
|
||||
static void place_cursor(int, int);
|
||||
static void place_cursor(int, int, int);
|
||||
static void screen_erase();
|
||||
static void clear_to_eol(void);
|
||||
static void clear_to_eos(void);
|
||||
@ -249,6 +256,7 @@ static void psbs(char *, ...); // Print Status Buf in standout mode
|
||||
static void ni(Byte *); // display messages
|
||||
static void edit_status(void); // show file status on status line
|
||||
static void redraw(int); // force a full screen refresh
|
||||
static void format_line(Byte*, Byte*, int);
|
||||
static void refresh(int); // update the terminal from screen[]
|
||||
|
||||
#ifdef BB_FEATURE_VI_SEARCH
|
||||
@ -261,9 +269,7 @@ static Byte *get_one_address(Byte *, int *); // get colon addr, if present
|
||||
static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present
|
||||
static void colon(Byte *); // execute the "colon" mode cmds
|
||||
#endif /* BB_FEATURE_VI_COLON */
|
||||
#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON)
|
||||
static Byte *get_input_line(Byte *); // get input line- use "status line"
|
||||
#endif /* BB_FEATURE_VI_SEARCH || BB_FEATURE_VI_COLON */
|
||||
#ifdef BB_FEATURE_VI_USE_SIGNALS
|
||||
static void winch_sig(int); // catch window size changes
|
||||
static void suspend_sig(int); // catch ctrl-Z
|
||||
@ -307,16 +313,23 @@ extern int vi_main(int argc, char **argv)
|
||||
int i;
|
||||
#endif /* BB_FEATURE_VI_YANKMARK */
|
||||
|
||||
CMrc= "\033[%d;%dH"; // Terminal Crusor motion ESC sequence
|
||||
CMup= "\033[A"; // move cursor up one line, same col
|
||||
CMdown="\n"; // move cursor down one line, same col
|
||||
Ceol= "\033[0K"; // Clear from cursor to end of line
|
||||
Ceos= "\033[0J"; // Clear from cursor to end of screen
|
||||
SOs = "\033[7m"; // Terminal standout mode on
|
||||
SOn = "\033[0m"; // Terminal standout mode off
|
||||
bell= "\007"; // Terminal bell sequence
|
||||
#ifdef BB_FEATURE_VI_CRASHME
|
||||
(void) srand((long) getpid());
|
||||
#endif /* BB_FEATURE_VI_CRASHME */
|
||||
status_buffer = (Byte *) malloc(200); // hold messages to user
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
readonly = FALSE;
|
||||
vi_readonly = readonly = FALSE;
|
||||
if (strncmp(argv[0], "view", 4) == 0) {
|
||||
readonly = TRUE;
|
||||
vi_readonly = TRUE;
|
||||
}
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
#ifdef BB_FEATURE_VI_SETOPTS
|
||||
@ -397,12 +410,12 @@ static void edit_file(Byte * fn)
|
||||
rawmode();
|
||||
rows = 24;
|
||||
columns = 80;
|
||||
ch= -1;
|
||||
#ifdef BB_FEATURE_VI_WIN_RESIZE
|
||||
window_size_get(0);
|
||||
#endif /* BB_FEATURE_VI_WIN_RESIZE */
|
||||
new_screen(rows, columns); // get memory for virtual screen
|
||||
|
||||
ch= 0;
|
||||
cnt = file_size(fn); // file size
|
||||
size = 2 * cnt; // 200% of file size
|
||||
new_text(size); // get a text[] buffer
|
||||
@ -484,7 +497,7 @@ static void edit_file(Byte * fn)
|
||||
ioq = ioq_start = last_modifying_cmd = 0;
|
||||
adding2q = 0;
|
||||
#endif /* BB_FEATURE_VI_DOT_CMD */
|
||||
redraw(TRUE);
|
||||
redraw(FALSE); // dont force every col re-draw
|
||||
show_status_line();
|
||||
|
||||
//------This is the main Vi cmd handling loop -----------------------
|
||||
@ -534,7 +547,7 @@ static void edit_file(Byte * fn)
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
place_cursor(rows, 0); // go to bottom of screen
|
||||
place_cursor(rows, 0, FALSE); // go to bottom of screen
|
||||
clear_to_eol(); // Erase to end of line
|
||||
cookmode();
|
||||
}
|
||||
@ -649,7 +662,7 @@ static void crash_dummy()
|
||||
i = (int) lrand48() % strlen(cmd);
|
||||
cm = cmd[i];
|
||||
if (strchr(":\024", cm))
|
||||
goto cd0; // dont allow these commands
|
||||
goto cd0; // dont allow colon or ctrl-T commands
|
||||
readbuffer[rbi++] = cm; // put cmd into input buffer
|
||||
|
||||
// now we have the command-
|
||||
@ -725,11 +738,9 @@ static void crash_test()
|
||||
|
||||
if (strlen(msg) > 0) {
|
||||
alarm(0);
|
||||
sprintf(buf, "\n\n%d: \'%c\' ", totalcmds, last_input_char);
|
||||
sprintf(buf, "\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
|
||||
totalcmds, last_input_char, msg, SOs, SOn);
|
||||
write(1, buf, strlen(buf));
|
||||
write(1, msg, strlen(msg));
|
||||
write(1, "\n\n\n", 3);
|
||||
write(1, "\033[7m[Hit return to continue]\033[0m", 32);
|
||||
while (read(0, d, 1) > 0) {
|
||||
if (d[0] == '\n' || d[0] == '\r')
|
||||
break;
|
||||
@ -844,7 +855,6 @@ static void do_cmd(Byte c)
|
||||
//case '_': // _-
|
||||
//case '`': // `-
|
||||
//case 'g': // g-
|
||||
//case 't': // t-
|
||||
//case 'u': // u- FIXME- there is no undo
|
||||
//case 'v': // v-
|
||||
default: // unrecognised command
|
||||
@ -904,7 +914,7 @@ static void do_cmd(Byte c)
|
||||
break;
|
||||
case 12: // ctrl-L force redraw whole screen
|
||||
case 18: // ctrl-R force redraw
|
||||
place_cursor(0, 0); // put cursor in correct place
|
||||
place_cursor(0, 0, FALSE); // put cursor in correct place
|
||||
clear_to_eos(); // tel terminal to erase display
|
||||
(void) mysleep(10);
|
||||
screen_erase(); // erase the internal screen buffer
|
||||
@ -924,7 +934,7 @@ static void do_cmd(Byte c)
|
||||
case 25: // ctrl-Y scroll up one line
|
||||
dot_scroll(1, -1);
|
||||
break;
|
||||
case 0x1b: // esc
|
||||
case 27: // esc
|
||||
if (cmd_mode == 0)
|
||||
indicate_error(c);
|
||||
cmd_mode = 0; // stop insrting
|
||||
@ -1053,8 +1063,9 @@ static void do_cmd(Byte c)
|
||||
//**** fall thru to ... 'i'
|
||||
case ';': // ;- look at rest of line for last forward char
|
||||
if (cmdcnt-- > 1) {
|
||||
do_cmd(c);
|
||||
do_cmd(';');
|
||||
} // repeat cnt
|
||||
if (last_forward_char == 0) break;
|
||||
q = dot + 1;
|
||||
while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
|
||||
q++;
|
||||
@ -1182,41 +1193,37 @@ static void do_cmd(Byte c)
|
||||
}
|
||||
break;
|
||||
case ':': // :- the colon mode commands
|
||||
#ifdef BB_FEATURE_VI_COLON
|
||||
p = get_input_line((Byte *) ":"); // get input line- use "status line"
|
||||
#ifdef BB_FEATURE_VI_COLON
|
||||
colon(p); // execute the command
|
||||
#else /* BB_FEATURE_VI_COLON */
|
||||
*status_buffer = '\0'; // clear the status buffer
|
||||
place_cursor(rows - 1, 0); // go to Status line, bottom of screen
|
||||
clear_to_eol(); // clear the line
|
||||
write(1, ":", 1); // write out the : prompt
|
||||
for (cnt = 0; cnt < 8; cnt++) {
|
||||
c1 = get_one_char();
|
||||
if (c1 == '\n' || c1 == '\r' || c1 == 27) {
|
||||
if (*p == ':')
|
||||
p++; // move past the ':'
|
||||
cnt = strlen((char *) p);
|
||||
if (cnt <= 0)
|
||||
break;
|
||||
}
|
||||
buf[cnt] = c1;
|
||||
buf[cnt + 1] = '\0';
|
||||
write(1, buf + cnt, 1); // echo the char
|
||||
}
|
||||
cnt = strlen((char *) buf);
|
||||
if (strncasecmp((char *) buf, "quit", cnt) == 0 ||
|
||||
strncasecmp((char *) buf, "q!", cnt) == 0) { // delete lines
|
||||
if (file_modified == TRUE && buf[1] != '!') {
|
||||
if (strncasecmp((char *) p, "quit", cnt) == 0 ||
|
||||
strncasecmp((char *) p, "q!", cnt) == 0) { // delete lines
|
||||
if (file_modified == TRUE && p[1] != '!') {
|
||||
psbs("No write since last change (:quit! overrides)");
|
||||
} else {
|
||||
editing = 0;
|
||||
}
|
||||
} else if (strncasecmp((char *) buf, "write", cnt) == 0 ||
|
||||
strncasecmp((char *) buf, "wq", cnt) == 0) {
|
||||
} else if (strncasecmp((char *) p, "write", cnt) == 0 ||
|
||||
strncasecmp((char *) p, "wq", cnt) == 0) {
|
||||
cnt = file_write(cfn, text, end - 1);
|
||||
file_modified = FALSE;
|
||||
psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt);
|
||||
if (buf[1] == 'q') {
|
||||
if (p[1] == 'q') {
|
||||
editing = 0;
|
||||
}
|
||||
} else if (strncasecmp((char *) p, "file", cnt) == 0 ) {
|
||||
edit_status(); // show current file status
|
||||
} else if (sscanf((char *) p, "%d", &j) > 0) {
|
||||
dot = find_line(j); // go to line # j
|
||||
dot_skip_over_ws();
|
||||
} else { // unrecognised cmd
|
||||
ni((Byte *) buf);
|
||||
ni((Byte *) p);
|
||||
}
|
||||
#endif /* BB_FEATURE_VI_COLON */
|
||||
break;
|
||||
@ -1344,7 +1351,7 @@ static void do_cmd(Byte c)
|
||||
dot = next_line(dot);
|
||||
break;
|
||||
case 'O': // O- open a empty line above
|
||||
// 0i\n\033-i
|
||||
// 0i\n ESC -i
|
||||
p = begin_line(dot);
|
||||
if (p[-1] == '\n') {
|
||||
dot_prev();
|
||||
@ -1353,7 +1360,7 @@ static void do_cmd(Byte c)
|
||||
dot = char_insert(dot, '\n');
|
||||
} else {
|
||||
dot_begin(); // 0
|
||||
dot = char_insert(dot, '\n'); // i\n\033
|
||||
dot = char_insert(dot, '\n'); // i\n ESC
|
||||
dot_prev(); // -
|
||||
}
|
||||
goto dc_i;
|
||||
@ -1390,6 +1397,7 @@ static void do_cmd(Byte c)
|
||||
}
|
||||
if (file_modified == TRUE
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
&& vi_readonly == FALSE
|
||||
&& readonly == FALSE
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
) {
|
||||
@ -1452,7 +1460,7 @@ static void do_cmd(Byte c)
|
||||
}
|
||||
}
|
||||
dot = yank_delete(p, q, 0, yf); // delete word
|
||||
} else if (strchr("^0bBeE$", c1)) {
|
||||
} else if (strchr("^0bBeEft$", c1)) {
|
||||
// single line copy text into a register and delete
|
||||
dot = yank_delete(p, q, 0, yf); // delete word
|
||||
} else if (strchr("cdykjHL%+-{}\r\n", c1)) {
|
||||
@ -1514,6 +1522,13 @@ static void do_cmd(Byte c)
|
||||
}
|
||||
end_cmd_q(); // stop adding to q
|
||||
break;
|
||||
case 't': // t- move to char prior to next x
|
||||
last_forward_char = get_one_char();
|
||||
do_cmd(';');
|
||||
if (*dot == last_forward_char)
|
||||
dot_left();
|
||||
last_forward_char= 0;
|
||||
break;
|
||||
case 'w': // w- forward a word
|
||||
if (cmdcnt-- > 1) {
|
||||
do_cmd(c);
|
||||
@ -1775,7 +1790,7 @@ static void colon(Byte * buf)
|
||||
} else if (strncmp((char *) cmd, "!", 1) == 0) { // run a cmd
|
||||
// :!ls run the <cmd>
|
||||
(void) alarm(0); // wait for input- no alarms
|
||||
place_cursor(rows - 1, 0); // go to Status line
|
||||
place_cursor(rows - 1, 0, FALSE); // go to Status line
|
||||
clear_to_eol(); // clear the line
|
||||
cookmode();
|
||||
system(orig_buf+1); // run the cmd
|
||||
@ -1877,7 +1892,7 @@ static void colon(Byte * buf)
|
||||
" %dL, %dC", cfn,
|
||||
(sr < 0 ? " [New file]" : ""),
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
(readonly == TRUE ? " [Read only]" : ""),
|
||||
((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
li, ch);
|
||||
} else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this
|
||||
@ -1896,7 +1911,7 @@ static void colon(Byte * buf)
|
||||
}
|
||||
} else if (strncasecmp((char *) cmd, "features", i) == 0) { // what features are available
|
||||
// print out values of all features
|
||||
place_cursor(rows - 1, 0); // go to Status line, bottom of screen
|
||||
place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
|
||||
clear_to_eol(); // clear the line
|
||||
cookmode();
|
||||
show_help();
|
||||
@ -1907,7 +1922,7 @@ static void colon(Byte * buf)
|
||||
q = begin_line(dot); // assume .,. for the range
|
||||
r = end_line(dot);
|
||||
}
|
||||
place_cursor(rows - 1, 0); // go to Status line, bottom of screen
|
||||
place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
|
||||
clear_to_eol(); // clear the line
|
||||
write(1, "\r\n", 2);
|
||||
for (; q <= r; q++) {
|
||||
@ -1979,7 +1994,7 @@ static void colon(Byte * buf)
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
" %dL, %dC", fn,
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
(readonly == TRUE ? " [Read only]" : ""),
|
||||
((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
li, ch);
|
||||
if (ch > 0) {
|
||||
@ -2001,13 +2016,16 @@ static void colon(Byte * buf)
|
||||
i = 0; // offset into args
|
||||
if (strlen((char *) args) == 0) {
|
||||
// print out values of all options
|
||||
place_cursor(rows - 1, 0); // go to Status line, bottom of screen
|
||||
place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
|
||||
clear_to_eol(); // clear the line
|
||||
printf("----------------------------------------\r\n");
|
||||
#ifdef BB_FEATURE_VI_SETOPTS
|
||||
if (!autoindent)
|
||||
printf("no");
|
||||
printf("autoindent ");
|
||||
if (!err_method)
|
||||
printf("no");
|
||||
printf("flash ");
|
||||
if (!ignorecase)
|
||||
printf("no");
|
||||
printf("ignorecase ");
|
||||
@ -2026,6 +2044,10 @@ static void colon(Byte * buf)
|
||||
strncasecmp((char *) args + i, "ai", 2) == 0) {
|
||||
autoindent = (i == 2) ? 0 : 1;
|
||||
}
|
||||
if (strncasecmp((char *) args + i, "flash", 5) == 0 ||
|
||||
strncasecmp((char *) args + i, "fl", 2) == 0) {
|
||||
err_method = (i == 2) ? 0 : 1;
|
||||
}
|
||||
if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 ||
|
||||
strncasecmp((char *) args + i, "ic", 2) == 0) {
|
||||
ignorecase = (i == 2) ? 0 : 1;
|
||||
@ -2096,7 +2118,7 @@ static void colon(Byte * buf)
|
||||
fn = args;
|
||||
}
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
if (readonly == TRUE && useforce == FALSE) {
|
||||
if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) {
|
||||
psbs("\"%s\" File is read only", fn);
|
||||
goto vc3;
|
||||
}
|
||||
@ -2452,10 +2474,18 @@ static Byte *bound_dot(Byte * p) // make sure text[0] <= P < "end"
|
||||
|
||||
static Byte *new_screen(int ro, int co)
|
||||
{
|
||||
int li;
|
||||
|
||||
if (screen != 0)
|
||||
free(screen);
|
||||
screensize = ro * co + 8;
|
||||
screen = (Byte *) malloc(screensize);
|
||||
// initialize the new screen. assume this will be a empty file.
|
||||
screen_erase();
|
||||
// non-existant text[] lines start with a tilde (~).
|
||||
for (li = 1; li < ro - 1; li++) {
|
||||
screen[(li * co) + 0] = '~';
|
||||
}
|
||||
return (screen);
|
||||
}
|
||||
|
||||
@ -2596,7 +2626,7 @@ static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
|
||||
cmd_mode = 0;
|
||||
cmdcnt = 0;
|
||||
end_cmd_q(); // stop adding to q
|
||||
*status_buffer = '\0'; // clear the status buffer
|
||||
strcpy((char *) status_buffer, " "); // clear the status buffer
|
||||
if (p[-1] != '\n') {
|
||||
p--;
|
||||
}
|
||||
@ -2667,7 +2697,7 @@ static Byte find_range(Byte ** start, Byte ** stop, Byte c)
|
||||
q = next_line(q);
|
||||
}
|
||||
q = end_line(q);
|
||||
} else if (strchr("^%$0bBeE", c)) {
|
||||
} else if (strchr("^%$0bBeEft", c)) {
|
||||
// These cmds operate on char positions
|
||||
do_cmd(c); // execute movement cmd
|
||||
q = dot;
|
||||
@ -2931,6 +2961,7 @@ static void show_help(void)
|
||||
printf("\tNamed buffers with \"x\n");
|
||||
#endif /* BB_FEATURE_VI_YANKMARK */
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
printf("\tReadonly if vi is called as \"view\"\n");
|
||||
printf("\tReadonly with -R command line arg\n");
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
#ifdef BB_FEATURE_VI_SET
|
||||
@ -3111,6 +3142,7 @@ static void rawmode(void)
|
||||
term_vi = term_orig;
|
||||
term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's
|
||||
term_vi.c_iflag &= (~IXON & ~ICRNL);
|
||||
term_vi.c_oflag &= (~ONLCR);
|
||||
term_vi.c_cc[VMIN] = 1;
|
||||
term_vi.c_cc[VTIME] = 0;
|
||||
erase_char = term_vi.c_cc[VERASE];
|
||||
@ -3172,7 +3204,7 @@ static void cont_sig(int sig)
|
||||
//----- Come here when we get a Suspend signal -------------------
|
||||
static void suspend_sig(int sig)
|
||||
{
|
||||
place_cursor(rows, 0); // go to bottom of screen
|
||||
place_cursor(rows - 1, 0, FALSE); // go to bottom of screen
|
||||
clear_to_eol(); // Erase to end of line
|
||||
cookmode(); // terminal to "cooked"
|
||||
|
||||
@ -3181,7 +3213,7 @@ static void suspend_sig(int sig)
|
||||
kill(getpid(), SIGTSTP);
|
||||
}
|
||||
|
||||
//----- Come here when we get a signal --------------------
|
||||
//----- Come here when we get a signal ---------------------------
|
||||
static void catch_sig(int sig)
|
||||
{
|
||||
signal(SIGHUP, catch_sig);
|
||||
@ -3382,7 +3414,6 @@ static Byte get_one_char()
|
||||
return (c); // return the char, where ever it came from
|
||||
}
|
||||
|
||||
#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON)
|
||||
static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
|
||||
{
|
||||
Byte buf[BUFSIZ];
|
||||
@ -3392,7 +3423,7 @@ static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
|
||||
|
||||
strcpy((char *) buf, (char *) prompt);
|
||||
*status_buffer = '\0'; // clear the status buffer
|
||||
place_cursor(rows - 1, 0); // go to Status line, bottom of screen
|
||||
place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
|
||||
clear_to_eol(); // clear the line
|
||||
write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt
|
||||
|
||||
@ -3421,7 +3452,6 @@ static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
|
||||
obufp = (Byte *) strdup((char *) buf);
|
||||
return (obufp);
|
||||
}
|
||||
#endif /* BB_FEATURE_VI_SEARCH || BB_FEATURE_VI_COLON */
|
||||
|
||||
static int file_size(Byte * fn) // what is the byte size of "fn"
|
||||
{
|
||||
@ -3465,9 +3495,15 @@ static int file_insert(Byte * fn, Byte * p, int size)
|
||||
}
|
||||
|
||||
// see if we can open the file
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
if (vi_readonly == TRUE) goto fi1; // do not try write-mode
|
||||
#endif
|
||||
fd = open((char *) fn, O_RDWR); // assume read & write
|
||||
if (fd < 0) {
|
||||
// could not open for writing- maybe file is read only
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
fi1:
|
||||
#endif
|
||||
fd = open((char *) fn, O_RDONLY); // try read-only
|
||||
if (fd < 0) {
|
||||
psbs("\"%s\" %s", fn, "could not open file");
|
||||
@ -3534,46 +3570,91 @@ static int file_write(Byte * fn, Byte * first, Byte * last)
|
||||
//
|
||||
|
||||
//----- Move the cursor to row x col (count from 0, not 1) -------
|
||||
static void place_cursor(int row, int col)
|
||||
static void place_cursor(int row, int col, int opti)
|
||||
{
|
||||
Byte buf[30];
|
||||
char cm1[BUFSIZ];
|
||||
char *cm;
|
||||
int l;
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
char cm2[BUFSIZ];
|
||||
Byte *screenp;
|
||||
// char cm3[BUFSIZ];
|
||||
int Rrow= last_row;
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
|
||||
if (row < 0)
|
||||
row = 0;
|
||||
if (row >= rows)
|
||||
row = rows - 1;
|
||||
if (col < 0)
|
||||
col = 0;
|
||||
if (col >= columns)
|
||||
col = columns - 1;
|
||||
sprintf((char *) buf, "%c[%d;%dH", 0x1b, row + 1, col + 1);
|
||||
l = strlen((char *) buf);
|
||||
write(1, buf, l);
|
||||
memset(cm1, '\0', BUFSIZ - 1); // clear the buffer
|
||||
|
||||
if (row < 0) row = 0;
|
||||
if (row >= rows) row = rows - 1;
|
||||
if (col < 0) col = 0;
|
||||
if (col >= columns) col = columns - 1;
|
||||
|
||||
//----- 1. Try the standard terminal ESC sequence
|
||||
sprintf((char *) cm1, CMrc, row + 1, col + 1);
|
||||
cm= cm1;
|
||||
if (opti == FALSE) goto pc0;
|
||||
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
//----- find the minimum # of chars to move cursor -------------
|
||||
//----- 2. Try moving with discreet chars (Newline, [back]space, ...)
|
||||
memset(cm2, '\0', BUFSIZ - 1); // clear the buffer
|
||||
|
||||
// move to the correct row
|
||||
while (row < Rrow) {
|
||||
// the cursor has to move up
|
||||
strcat(cm2, CMup);
|
||||
Rrow--;
|
||||
}
|
||||
while (row > Rrow) {
|
||||
// the cursor has to move down
|
||||
strcat(cm2, CMdown);
|
||||
Rrow++;
|
||||
}
|
||||
|
||||
// now move to the correct column
|
||||
strcat(cm2, "\r"); // start at col 0
|
||||
// just send out orignal source char to get to correct place
|
||||
screenp = &screen[row * columns]; // start of screen line
|
||||
strncat(cm2, screenp, col);
|
||||
|
||||
//----- 3. Try some other way of moving cursor
|
||||
//---------------------------------------------
|
||||
|
||||
// pick the shortest cursor motion to send out
|
||||
cm= cm1;
|
||||
if (strlen(cm2) < strlen(cm)) {
|
||||
cm= cm2;
|
||||
} /* else if (strlen(cm3) < strlen(cm)) {
|
||||
cm= cm3;
|
||||
} */
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
pc0:
|
||||
l= strlen(cm);
|
||||
if (l) write(1, cm, l); // move the cursor
|
||||
}
|
||||
|
||||
//----- Erase from cursor to end of line -----------------------
|
||||
static void clear_to_eol()
|
||||
{
|
||||
write(1, "\033[0K", 4); // Erase from cursor to end of line
|
||||
write(1, Ceol, strlen(Ceol)); // Erase from cursor to end of line
|
||||
}
|
||||
|
||||
//----- Erase from cursor to end of screen -----------------------
|
||||
static void clear_to_eos()
|
||||
{
|
||||
write(1, "\033[0J", 4); // Erase from cursor to end of screen
|
||||
write(1, Ceos, strlen(Ceos)); // Erase from cursor to end of screen
|
||||
}
|
||||
|
||||
//----- Start standout mode ------------------------------------
|
||||
static void standout_start() // send "start reverse video" sequence
|
||||
{
|
||||
write(1, "\033[7m", 4); // Start reverse video mode
|
||||
write(1, SOs, strlen(SOs)); // Start reverse video mode
|
||||
}
|
||||
|
||||
//----- End standout mode --------------------------------------
|
||||
static void standout_end() // send "end reverse video" sequence
|
||||
{
|
||||
write(1, "\033[0m", 4); // End reverse video mode
|
||||
write(1, SOn, strlen(SOn)); // End reverse video mode
|
||||
}
|
||||
|
||||
//----- Flash the screen --------------------------------------
|
||||
@ -3588,7 +3669,7 @@ static void flash(int h)
|
||||
|
||||
static void beep()
|
||||
{
|
||||
write(1, "\007", 1); // send out a bell character
|
||||
write(1, bell, strlen(bell)); // send out a bell character
|
||||
}
|
||||
|
||||
static void indicate_error(char c)
|
||||
@ -3608,25 +3689,25 @@ static void indicate_error(char c)
|
||||
//----- Erase the Screen[] memory ------------------------------
|
||||
static void screen_erase()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < screensize; i++) {
|
||||
screen[i] = '\0';
|
||||
}
|
||||
memset(screen, ' ', screensize); // clear new screen
|
||||
}
|
||||
|
||||
//----- Draw the status line at bottom of the screen -------------
|
||||
static void show_status_line(void)
|
||||
{
|
||||
int cnt;
|
||||
static int last_cksum;
|
||||
int l, cnt, cksum;
|
||||
|
||||
cnt = strlen((char *) status_buffer);
|
||||
place_cursor(rows - 1, 0); // put cursor on status line
|
||||
if (cnt > 0) {
|
||||
for (cksum= l= 0; l < cnt; l++) { cksum += (int)(status_buffer[l]); }
|
||||
// don't write the status line unless it changes
|
||||
if (cnt > 0 && last_cksum != cksum) {
|
||||
last_cksum= cksum; // remember if we have seen this line
|
||||
place_cursor(rows - 1, 0, FALSE); // put cursor on status line
|
||||
write(1, status_buffer, cnt);
|
||||
}
|
||||
clear_to_eol();
|
||||
place_cursor(crow, ccol); // put cursor back in correct place
|
||||
place_cursor(crow, ccol, FALSE); // put cursor back in correct place
|
||||
}
|
||||
}
|
||||
|
||||
//----- format the status buffer, the bottom line of screen ------
|
||||
@ -3636,10 +3717,10 @@ static void psbs(char *format, ...)
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
strcpy((char *) status_buffer, "\033[7m"); // Terminal standout mode on
|
||||
strcpy((char *) status_buffer, SOs); // Terminal standout mode on
|
||||
vsprintf((char *) status_buffer + strlen((char *) status_buffer), format,
|
||||
args);
|
||||
strcat((char *) status_buffer, "\033[0m"); // Terminal standout mode off
|
||||
strcat((char *) status_buffer, SOn); // Terminal standout mode off
|
||||
va_end(args);
|
||||
|
||||
return;
|
||||
@ -3686,7 +3767,7 @@ static void edit_status(void) // show file status on status line
|
||||
"%s line %d of %d --%d%%--",
|
||||
(cfn != 0 ? (char *) cfn : "No file"),
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
(readonly == TRUE ? " [Read only]" : ""),
|
||||
((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
(file_modified == TRUE ? " [modified]" : ""),
|
||||
cur, tot, percent);
|
||||
@ -3695,12 +3776,50 @@ static void edit_status(void) // show file status on status line
|
||||
//----- Force refresh of all Lines -----------------------------
|
||||
static void redraw(int full_screen)
|
||||
{
|
||||
place_cursor(0, 0); // put cursor in correct place
|
||||
place_cursor(0, 0, FALSE); // put cursor in correct place
|
||||
clear_to_eos(); // tel terminal to erase display
|
||||
screen_erase(); // erase the internal screen buffer
|
||||
refresh(full_screen); // this will redraw the entire display
|
||||
}
|
||||
|
||||
//----- Format a text[] line into a buffer ---------------------
|
||||
static void format_line(Byte *dest, Byte *src, int li)
|
||||
{
|
||||
int co;
|
||||
Byte c;
|
||||
|
||||
for (co= 0; co < MAX_SCR_COLS; co++) {
|
||||
c= ' '; // assume blank
|
||||
if (li > 0 && co == 0) {
|
||||
c = '~'; // not first line, assume Tilde
|
||||
}
|
||||
// are there chars in text[] and have we gone past the end
|
||||
if (text < end && src < end) {
|
||||
c = *src++;
|
||||
}
|
||||
if (c == '\n')
|
||||
break;
|
||||
if (c < ' ' || c > '~') {
|
||||
if (c == '\t') {
|
||||
c = ' ';
|
||||
// co % 8 != 7
|
||||
for (; (co % tabstop) != (tabstop - 1); co++) {
|
||||
dest[co] = c;
|
||||
}
|
||||
} else {
|
||||
dest[co++] = '^';
|
||||
c |= '@'; // make it visible
|
||||
c &= 0x7f; // get rid of hi bit
|
||||
}
|
||||
}
|
||||
// the co++ is done here so that the column will
|
||||
// not be overwritten when we blank-out the rest of line
|
||||
dest[co] = c;
|
||||
if (src >= end)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----- Refresh the changed screen lines -----------------------
|
||||
// Copy the source line from text[] into the buffer and note
|
||||
// if the current screenline is different from the new buffer.
|
||||
@ -3709,97 +3828,102 @@ static void redraw(int full_screen)
|
||||
static void refresh(int full_screen)
|
||||
{
|
||||
static int old_offset;
|
||||
int li, co, changed;
|
||||
Byte c, buf[MAX_SCR_COLS];
|
||||
int li, changed;
|
||||
Byte buf[MAX_SCR_COLS];
|
||||
Byte *tp, *sp; // pointer into text[] and screen[]
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
int last_li= -2; // last line that changed- for optimizing cursor movement
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
|
||||
#ifdef BB_FEATURE_VI_WIN_RESIZE
|
||||
window_size_get(0);
|
||||
#endif /* BB_FEATURE_VI_WIN_RESIZE */
|
||||
sync_cursor(dot, &crow, &ccol);
|
||||
sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot")
|
||||
tp = screenbegin; // index into text[] of top line
|
||||
|
||||
// compare text[] to screen[] and mark screen[] lines that need updating
|
||||
for (li = 0; li < rows - 1; li++) {
|
||||
// format current text line into buf with "columns" wide
|
||||
for (co = 0; co < columns + offset;) {
|
||||
c = ' '; // assume blank
|
||||
if (li > 0 && co == 0) {
|
||||
c = '~'; // not first line, assume Tilde
|
||||
}
|
||||
// are there chars in text[]
|
||||
// and have we gone past the end
|
||||
if (text < end && tp < end) {
|
||||
c = *tp++;
|
||||
}
|
||||
if (c == '\n')
|
||||
break;
|
||||
if (c < ' ' || c > '~') {
|
||||
if (c == '\t') {
|
||||
c = ' ';
|
||||
// co % 8 != 7
|
||||
for (; (co % tabstop) != (tabstop - 1); co++) {
|
||||
buf[co] = c;
|
||||
}
|
||||
} else {
|
||||
buf[co++] = '^';
|
||||
c |= '@'; // make it visible
|
||||
c &= 0x7f; // get rid of hi bit
|
||||
}
|
||||
}
|
||||
// the co++ is done here so that the column will
|
||||
// not be overwritten when we blank-out the rest of line
|
||||
buf[co++] = c;
|
||||
if (tp >= end)
|
||||
break;
|
||||
}
|
||||
if (co >= columns + offset) {
|
||||
int cs, ce; // column start & end
|
||||
memset(buf, ' ', MAX_SCR_COLS); // blank-out the buffer
|
||||
buf[MAX_SCR_COLS-1] = 0; // NULL terminate the buffer
|
||||
// format current text line into buf
|
||||
format_line(buf, tp, li);
|
||||
|
||||
// skip to the end of the current text[] line
|
||||
while (tp < end && *tp++ != '\n');
|
||||
}
|
||||
// try to keep the cursor near it's current position
|
||||
// remember how many chars in this row- where the cursor sits
|
||||
// blank out the rest of the buffer
|
||||
while (co < MAX_SCR_COLS - 1) {
|
||||
buf[co++] = ' ';
|
||||
}
|
||||
buf[co++] = 0; // NULL terminate the buffer
|
||||
while (tp < end && *tp++ != '\n') /*no-op*/ ;
|
||||
|
||||
// if necessary, update virtual screen[] and terminal from buf[]
|
||||
// see if there are any changes between vitual screen and buf
|
||||
changed = FALSE; // assume no change
|
||||
cs= 0;
|
||||
ce= columns-1;
|
||||
sp = &screen[li * columns]; // start of screen line
|
||||
for (co = 0; co < columns; co++) {
|
||||
if (sp[co] != buf[co + offset]) {
|
||||
sp[co] = buf[co + offset];
|
||||
if (full_screen == TRUE) {
|
||||
// force re-draw of every single column from 0 - columns-1
|
||||
goto re0;
|
||||
}
|
||||
// compare newly formatted buffer with virtual screen
|
||||
// look forward for first difference between buf and screen
|
||||
for ( ; cs <= ce; cs++) {
|
||||
if (buf[cs + offset] != sp[cs]) {
|
||||
changed = TRUE; // mark for redraw
|
||||
}
|
||||
}
|
||||
// if horz offset has changed, force a redraw
|
||||
if (offset != old_offset)
|
||||
changed = TRUE;
|
||||
|
||||
// write all marked screen lines out to terminal
|
||||
if (changed == TRUE) {
|
||||
place_cursor(li, 0); // put cursor in correct place
|
||||
clear_to_eol(); // Erase to end of line
|
||||
if (full_screen == FALSE) {
|
||||
// don't redraw every column on terminal
|
||||
// look backwards for last non-blank
|
||||
for (co = columns + offset; co >= 0; co--) {
|
||||
// break;
|
||||
if (buf[co] != ' ')
|
||||
break;
|
||||
}
|
||||
co++;
|
||||
} else {
|
||||
// redraw every column on terminal
|
||||
co = columns;
|
||||
}
|
||||
|
||||
// look backward for last difference between buf and screen
|
||||
for ( ; ce >= cs; ce--) {
|
||||
if (buf[ce + offset] != sp[ce]) {
|
||||
changed = TRUE; // mark for redraw
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now, cs is index of first diff, and ce is index of last diff
|
||||
|
||||
// if horz offset has changed, force a redraw
|
||||
if (offset != old_offset) {
|
||||
re0:
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
// make a sanity check of columns indexes
|
||||
if (cs < 0) cs= 0;
|
||||
if (ce > columns-1) ce= columns-1;
|
||||
if (cs > ce) { cs= 0; ce= columns-1; }
|
||||
// is there a change between vitual screen and buf
|
||||
if (changed == TRUE) {
|
||||
// copy changed part of buffer to virtual screen
|
||||
memmove(sp+cs, buf+(cs+offset), ce-cs+1);
|
||||
|
||||
// move cursor to column of first change
|
||||
if (offset != old_offset) {
|
||||
// opti_cur_move is still too stupid
|
||||
// to handle offsets correctly
|
||||
place_cursor(li, cs, FALSE);
|
||||
} else {
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
// if this just the next line
|
||||
// try to optimize cursor movement
|
||||
// otherwise, use standard ESC sequence
|
||||
place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE);
|
||||
last_li= li;
|
||||
#else /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
place_cursor(li, cs, FALSE); // use standard ESC sequence
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
}
|
||||
|
||||
// write line out to terminal
|
||||
write(1, buf + offset, co);
|
||||
write(1, sp+cs, ce-cs+1);
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
last_row = li;
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
}
|
||||
}
|
||||
|
||||
place_cursor(crow, ccol);
|
||||
place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE);
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
last_row = crow;
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
|
||||
if (offset != old_offset)
|
||||
old_offset = offset;
|
||||
}
|
||||
|
446
vi.c
446
vi.c
@ -19,13 +19,13 @@
|
||||
*/
|
||||
|
||||
char *vi_Version =
|
||||
"$Id: vi.c,v 1.5 2001/04/26 15:56:47 andersen Exp $";
|
||||
"$Id: vi.c,v 1.6 2001/05/07 17:37:43 andersen Exp $";
|
||||
|
||||
/*
|
||||
* To compile for standalone use:
|
||||
* gcc -Wall -Os -s -DSTANDALONE -o vi vi.c
|
||||
* or
|
||||
* gcc -Wall -Os -s -DSTANDALONE -DCRASHME -o vi vi.c # include testing features
|
||||
* gcc -Wall -Os -s -DSTANDALONE -DBB_FEATURE_VI_CRASHME -o vi vi.c # include testing features
|
||||
* strip vi
|
||||
*/
|
||||
|
||||
@ -144,7 +144,11 @@ static struct timeval tv; // use select() for small sleeps
|
||||
static char erase_char; // the users erase character
|
||||
static int rows, columns; // the terminal screen is this size
|
||||
static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset
|
||||
static char *SOs, *SOn;
|
||||
static char *SOs, *SOn; // terminal standout start/normal ESC sequence
|
||||
static char *bell; // terminal bell sequence
|
||||
static char *Ceol, *Ceos; // Clear-end-of-line and Clear-end-of-screen ESC sequence
|
||||
static char *CMrc; // Cursor motion arbitrary destination ESC sequence
|
||||
static char *CMup, *CMdown; // Cursor motion up and down ESC sequence
|
||||
static Byte *status_buffer; // mesages to the user
|
||||
static Byte last_input_char; // last char read from user
|
||||
static Byte last_forward_char; // last char searched for with 'f'
|
||||
@ -157,6 +161,9 @@ static Byte *dot; // where all the action takes place
|
||||
static int tabstop;
|
||||
static struct termios term_orig, term_vi; // remember what the cooked mode was
|
||||
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
static int last_row; // where the cursor was last moved to
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
#ifdef BB_FEATURE_VI_USE_SIGNALS
|
||||
static jmp_buf restart; // catch_sig()
|
||||
#endif /* BB_FEATURE_VI_USE_SIGNALS */
|
||||
@ -172,7 +179,7 @@ static Byte *ioq, *ioq_start; // pointer to string for get_one_char to "read"
|
||||
static Byte *modifying_cmds; // cmds that modify text[]
|
||||
#endif /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
static int readonly;
|
||||
static int vi_readonly, readonly;
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
#ifdef BB_FEATURE_VI_SETOPTS
|
||||
static int autoindent;
|
||||
@ -234,7 +241,7 @@ static Byte get_one_char(void); // read 1 char from stdin
|
||||
static int file_size(Byte *); // what is the byte size of "fn"
|
||||
static int file_insert(Byte *, Byte *, int);
|
||||
static int file_write(Byte *, Byte *, Byte *);
|
||||
static void place_cursor(int, int);
|
||||
static void place_cursor(int, int, int);
|
||||
static void screen_erase();
|
||||
static void clear_to_eol(void);
|
||||
static void clear_to_eos(void);
|
||||
@ -249,6 +256,7 @@ static void psbs(char *, ...); // Print Status Buf in standout mode
|
||||
static void ni(Byte *); // display messages
|
||||
static void edit_status(void); // show file status on status line
|
||||
static void redraw(int); // force a full screen refresh
|
||||
static void format_line(Byte*, Byte*, int);
|
||||
static void refresh(int); // update the terminal from screen[]
|
||||
|
||||
#ifdef BB_FEATURE_VI_SEARCH
|
||||
@ -261,9 +269,7 @@ static Byte *get_one_address(Byte *, int *); // get colon addr, if present
|
||||
static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present
|
||||
static void colon(Byte *); // execute the "colon" mode cmds
|
||||
#endif /* BB_FEATURE_VI_COLON */
|
||||
#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON)
|
||||
static Byte *get_input_line(Byte *); // get input line- use "status line"
|
||||
#endif /* BB_FEATURE_VI_SEARCH || BB_FEATURE_VI_COLON */
|
||||
#ifdef BB_FEATURE_VI_USE_SIGNALS
|
||||
static void winch_sig(int); // catch window size changes
|
||||
static void suspend_sig(int); // catch ctrl-Z
|
||||
@ -307,16 +313,23 @@ extern int vi_main(int argc, char **argv)
|
||||
int i;
|
||||
#endif /* BB_FEATURE_VI_YANKMARK */
|
||||
|
||||
CMrc= "\033[%d;%dH"; // Terminal Crusor motion ESC sequence
|
||||
CMup= "\033[A"; // move cursor up one line, same col
|
||||
CMdown="\n"; // move cursor down one line, same col
|
||||
Ceol= "\033[0K"; // Clear from cursor to end of line
|
||||
Ceos= "\033[0J"; // Clear from cursor to end of screen
|
||||
SOs = "\033[7m"; // Terminal standout mode on
|
||||
SOn = "\033[0m"; // Terminal standout mode off
|
||||
bell= "\007"; // Terminal bell sequence
|
||||
#ifdef BB_FEATURE_VI_CRASHME
|
||||
(void) srand((long) getpid());
|
||||
#endif /* BB_FEATURE_VI_CRASHME */
|
||||
status_buffer = (Byte *) malloc(200); // hold messages to user
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
readonly = FALSE;
|
||||
vi_readonly = readonly = FALSE;
|
||||
if (strncmp(argv[0], "view", 4) == 0) {
|
||||
readonly = TRUE;
|
||||
vi_readonly = TRUE;
|
||||
}
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
#ifdef BB_FEATURE_VI_SETOPTS
|
||||
@ -397,12 +410,12 @@ static void edit_file(Byte * fn)
|
||||
rawmode();
|
||||
rows = 24;
|
||||
columns = 80;
|
||||
ch= -1;
|
||||
#ifdef BB_FEATURE_VI_WIN_RESIZE
|
||||
window_size_get(0);
|
||||
#endif /* BB_FEATURE_VI_WIN_RESIZE */
|
||||
new_screen(rows, columns); // get memory for virtual screen
|
||||
|
||||
ch= 0;
|
||||
cnt = file_size(fn); // file size
|
||||
size = 2 * cnt; // 200% of file size
|
||||
new_text(size); // get a text[] buffer
|
||||
@ -484,7 +497,7 @@ static void edit_file(Byte * fn)
|
||||
ioq = ioq_start = last_modifying_cmd = 0;
|
||||
adding2q = 0;
|
||||
#endif /* BB_FEATURE_VI_DOT_CMD */
|
||||
redraw(TRUE);
|
||||
redraw(FALSE); // dont force every col re-draw
|
||||
show_status_line();
|
||||
|
||||
//------This is the main Vi cmd handling loop -----------------------
|
||||
@ -534,7 +547,7 @@ static void edit_file(Byte * fn)
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
place_cursor(rows, 0); // go to bottom of screen
|
||||
place_cursor(rows, 0, FALSE); // go to bottom of screen
|
||||
clear_to_eol(); // Erase to end of line
|
||||
cookmode();
|
||||
}
|
||||
@ -649,7 +662,7 @@ static void crash_dummy()
|
||||
i = (int) lrand48() % strlen(cmd);
|
||||
cm = cmd[i];
|
||||
if (strchr(":\024", cm))
|
||||
goto cd0; // dont allow these commands
|
||||
goto cd0; // dont allow colon or ctrl-T commands
|
||||
readbuffer[rbi++] = cm; // put cmd into input buffer
|
||||
|
||||
// now we have the command-
|
||||
@ -725,11 +738,9 @@ static void crash_test()
|
||||
|
||||
if (strlen(msg) > 0) {
|
||||
alarm(0);
|
||||
sprintf(buf, "\n\n%d: \'%c\' ", totalcmds, last_input_char);
|
||||
sprintf(buf, "\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
|
||||
totalcmds, last_input_char, msg, SOs, SOn);
|
||||
write(1, buf, strlen(buf));
|
||||
write(1, msg, strlen(msg));
|
||||
write(1, "\n\n\n", 3);
|
||||
write(1, "\033[7m[Hit return to continue]\033[0m", 32);
|
||||
while (read(0, d, 1) > 0) {
|
||||
if (d[0] == '\n' || d[0] == '\r')
|
||||
break;
|
||||
@ -844,7 +855,6 @@ static void do_cmd(Byte c)
|
||||
//case '_': // _-
|
||||
//case '`': // `-
|
||||
//case 'g': // g-
|
||||
//case 't': // t-
|
||||
//case 'u': // u- FIXME- there is no undo
|
||||
//case 'v': // v-
|
||||
default: // unrecognised command
|
||||
@ -904,7 +914,7 @@ static void do_cmd(Byte c)
|
||||
break;
|
||||
case 12: // ctrl-L force redraw whole screen
|
||||
case 18: // ctrl-R force redraw
|
||||
place_cursor(0, 0); // put cursor in correct place
|
||||
place_cursor(0, 0, FALSE); // put cursor in correct place
|
||||
clear_to_eos(); // tel terminal to erase display
|
||||
(void) mysleep(10);
|
||||
screen_erase(); // erase the internal screen buffer
|
||||
@ -924,7 +934,7 @@ static void do_cmd(Byte c)
|
||||
case 25: // ctrl-Y scroll up one line
|
||||
dot_scroll(1, -1);
|
||||
break;
|
||||
case 0x1b: // esc
|
||||
case 27: // esc
|
||||
if (cmd_mode == 0)
|
||||
indicate_error(c);
|
||||
cmd_mode = 0; // stop insrting
|
||||
@ -1053,8 +1063,9 @@ static void do_cmd(Byte c)
|
||||
//**** fall thru to ... 'i'
|
||||
case ';': // ;- look at rest of line for last forward char
|
||||
if (cmdcnt-- > 1) {
|
||||
do_cmd(c);
|
||||
do_cmd(';');
|
||||
} // repeat cnt
|
||||
if (last_forward_char == 0) break;
|
||||
q = dot + 1;
|
||||
while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
|
||||
q++;
|
||||
@ -1182,41 +1193,37 @@ static void do_cmd(Byte c)
|
||||
}
|
||||
break;
|
||||
case ':': // :- the colon mode commands
|
||||
#ifdef BB_FEATURE_VI_COLON
|
||||
p = get_input_line((Byte *) ":"); // get input line- use "status line"
|
||||
#ifdef BB_FEATURE_VI_COLON
|
||||
colon(p); // execute the command
|
||||
#else /* BB_FEATURE_VI_COLON */
|
||||
*status_buffer = '\0'; // clear the status buffer
|
||||
place_cursor(rows - 1, 0); // go to Status line, bottom of screen
|
||||
clear_to_eol(); // clear the line
|
||||
write(1, ":", 1); // write out the : prompt
|
||||
for (cnt = 0; cnt < 8; cnt++) {
|
||||
c1 = get_one_char();
|
||||
if (c1 == '\n' || c1 == '\r' || c1 == 27) {
|
||||
if (*p == ':')
|
||||
p++; // move past the ':'
|
||||
cnt = strlen((char *) p);
|
||||
if (cnt <= 0)
|
||||
break;
|
||||
}
|
||||
buf[cnt] = c1;
|
||||
buf[cnt + 1] = '\0';
|
||||
write(1, buf + cnt, 1); // echo the char
|
||||
}
|
||||
cnt = strlen((char *) buf);
|
||||
if (strncasecmp((char *) buf, "quit", cnt) == 0 ||
|
||||
strncasecmp((char *) buf, "q!", cnt) == 0) { // delete lines
|
||||
if (file_modified == TRUE && buf[1] != '!') {
|
||||
if (strncasecmp((char *) p, "quit", cnt) == 0 ||
|
||||
strncasecmp((char *) p, "q!", cnt) == 0) { // delete lines
|
||||
if (file_modified == TRUE && p[1] != '!') {
|
||||
psbs("No write since last change (:quit! overrides)");
|
||||
} else {
|
||||
editing = 0;
|
||||
}
|
||||
} else if (strncasecmp((char *) buf, "write", cnt) == 0 ||
|
||||
strncasecmp((char *) buf, "wq", cnt) == 0) {
|
||||
} else if (strncasecmp((char *) p, "write", cnt) == 0 ||
|
||||
strncasecmp((char *) p, "wq", cnt) == 0) {
|
||||
cnt = file_write(cfn, text, end - 1);
|
||||
file_modified = FALSE;
|
||||
psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt);
|
||||
if (buf[1] == 'q') {
|
||||
if (p[1] == 'q') {
|
||||
editing = 0;
|
||||
}
|
||||
} else if (strncasecmp((char *) p, "file", cnt) == 0 ) {
|
||||
edit_status(); // show current file status
|
||||
} else if (sscanf((char *) p, "%d", &j) > 0) {
|
||||
dot = find_line(j); // go to line # j
|
||||
dot_skip_over_ws();
|
||||
} else { // unrecognised cmd
|
||||
ni((Byte *) buf);
|
||||
ni((Byte *) p);
|
||||
}
|
||||
#endif /* BB_FEATURE_VI_COLON */
|
||||
break;
|
||||
@ -1344,7 +1351,7 @@ static void do_cmd(Byte c)
|
||||
dot = next_line(dot);
|
||||
break;
|
||||
case 'O': // O- open a empty line above
|
||||
// 0i\n\033-i
|
||||
// 0i\n ESC -i
|
||||
p = begin_line(dot);
|
||||
if (p[-1] == '\n') {
|
||||
dot_prev();
|
||||
@ -1353,7 +1360,7 @@ static void do_cmd(Byte c)
|
||||
dot = char_insert(dot, '\n');
|
||||
} else {
|
||||
dot_begin(); // 0
|
||||
dot = char_insert(dot, '\n'); // i\n\033
|
||||
dot = char_insert(dot, '\n'); // i\n ESC
|
||||
dot_prev(); // -
|
||||
}
|
||||
goto dc_i;
|
||||
@ -1390,6 +1397,7 @@ static void do_cmd(Byte c)
|
||||
}
|
||||
if (file_modified == TRUE
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
&& vi_readonly == FALSE
|
||||
&& readonly == FALSE
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
) {
|
||||
@ -1452,7 +1460,7 @@ static void do_cmd(Byte c)
|
||||
}
|
||||
}
|
||||
dot = yank_delete(p, q, 0, yf); // delete word
|
||||
} else if (strchr("^0bBeE$", c1)) {
|
||||
} else if (strchr("^0bBeEft$", c1)) {
|
||||
// single line copy text into a register and delete
|
||||
dot = yank_delete(p, q, 0, yf); // delete word
|
||||
} else if (strchr("cdykjHL%+-{}\r\n", c1)) {
|
||||
@ -1514,6 +1522,13 @@ static void do_cmd(Byte c)
|
||||
}
|
||||
end_cmd_q(); // stop adding to q
|
||||
break;
|
||||
case 't': // t- move to char prior to next x
|
||||
last_forward_char = get_one_char();
|
||||
do_cmd(';');
|
||||
if (*dot == last_forward_char)
|
||||
dot_left();
|
||||
last_forward_char= 0;
|
||||
break;
|
||||
case 'w': // w- forward a word
|
||||
if (cmdcnt-- > 1) {
|
||||
do_cmd(c);
|
||||
@ -1775,7 +1790,7 @@ static void colon(Byte * buf)
|
||||
} else if (strncmp((char *) cmd, "!", 1) == 0) { // run a cmd
|
||||
// :!ls run the <cmd>
|
||||
(void) alarm(0); // wait for input- no alarms
|
||||
place_cursor(rows - 1, 0); // go to Status line
|
||||
place_cursor(rows - 1, 0, FALSE); // go to Status line
|
||||
clear_to_eol(); // clear the line
|
||||
cookmode();
|
||||
system(orig_buf+1); // run the cmd
|
||||
@ -1877,7 +1892,7 @@ static void colon(Byte * buf)
|
||||
" %dL, %dC", cfn,
|
||||
(sr < 0 ? " [New file]" : ""),
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
(readonly == TRUE ? " [Read only]" : ""),
|
||||
((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
li, ch);
|
||||
} else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this
|
||||
@ -1896,7 +1911,7 @@ static void colon(Byte * buf)
|
||||
}
|
||||
} else if (strncasecmp((char *) cmd, "features", i) == 0) { // what features are available
|
||||
// print out values of all features
|
||||
place_cursor(rows - 1, 0); // go to Status line, bottom of screen
|
||||
place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
|
||||
clear_to_eol(); // clear the line
|
||||
cookmode();
|
||||
show_help();
|
||||
@ -1907,7 +1922,7 @@ static void colon(Byte * buf)
|
||||
q = begin_line(dot); // assume .,. for the range
|
||||
r = end_line(dot);
|
||||
}
|
||||
place_cursor(rows - 1, 0); // go to Status line, bottom of screen
|
||||
place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
|
||||
clear_to_eol(); // clear the line
|
||||
write(1, "\r\n", 2);
|
||||
for (; q <= r; q++) {
|
||||
@ -1979,7 +1994,7 @@ static void colon(Byte * buf)
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
" %dL, %dC", fn,
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
(readonly == TRUE ? " [Read only]" : ""),
|
||||
((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
li, ch);
|
||||
if (ch > 0) {
|
||||
@ -2001,13 +2016,16 @@ static void colon(Byte * buf)
|
||||
i = 0; // offset into args
|
||||
if (strlen((char *) args) == 0) {
|
||||
// print out values of all options
|
||||
place_cursor(rows - 1, 0); // go to Status line, bottom of screen
|
||||
place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
|
||||
clear_to_eol(); // clear the line
|
||||
printf("----------------------------------------\r\n");
|
||||
#ifdef BB_FEATURE_VI_SETOPTS
|
||||
if (!autoindent)
|
||||
printf("no");
|
||||
printf("autoindent ");
|
||||
if (!err_method)
|
||||
printf("no");
|
||||
printf("flash ");
|
||||
if (!ignorecase)
|
||||
printf("no");
|
||||
printf("ignorecase ");
|
||||
@ -2026,6 +2044,10 @@ static void colon(Byte * buf)
|
||||
strncasecmp((char *) args + i, "ai", 2) == 0) {
|
||||
autoindent = (i == 2) ? 0 : 1;
|
||||
}
|
||||
if (strncasecmp((char *) args + i, "flash", 5) == 0 ||
|
||||
strncasecmp((char *) args + i, "fl", 2) == 0) {
|
||||
err_method = (i == 2) ? 0 : 1;
|
||||
}
|
||||
if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 ||
|
||||
strncasecmp((char *) args + i, "ic", 2) == 0) {
|
||||
ignorecase = (i == 2) ? 0 : 1;
|
||||
@ -2096,7 +2118,7 @@ static void colon(Byte * buf)
|
||||
fn = args;
|
||||
}
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
if (readonly == TRUE && useforce == FALSE) {
|
||||
if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) {
|
||||
psbs("\"%s\" File is read only", fn);
|
||||
goto vc3;
|
||||
}
|
||||
@ -2452,10 +2474,18 @@ static Byte *bound_dot(Byte * p) // make sure text[0] <= P < "end"
|
||||
|
||||
static Byte *new_screen(int ro, int co)
|
||||
{
|
||||
int li;
|
||||
|
||||
if (screen != 0)
|
||||
free(screen);
|
||||
screensize = ro * co + 8;
|
||||
screen = (Byte *) malloc(screensize);
|
||||
// initialize the new screen. assume this will be a empty file.
|
||||
screen_erase();
|
||||
// non-existant text[] lines start with a tilde (~).
|
||||
for (li = 1; li < ro - 1; li++) {
|
||||
screen[(li * co) + 0] = '~';
|
||||
}
|
||||
return (screen);
|
||||
}
|
||||
|
||||
@ -2596,7 +2626,7 @@ static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
|
||||
cmd_mode = 0;
|
||||
cmdcnt = 0;
|
||||
end_cmd_q(); // stop adding to q
|
||||
*status_buffer = '\0'; // clear the status buffer
|
||||
strcpy((char *) status_buffer, " "); // clear the status buffer
|
||||
if (p[-1] != '\n') {
|
||||
p--;
|
||||
}
|
||||
@ -2667,7 +2697,7 @@ static Byte find_range(Byte ** start, Byte ** stop, Byte c)
|
||||
q = next_line(q);
|
||||
}
|
||||
q = end_line(q);
|
||||
} else if (strchr("^%$0bBeE", c)) {
|
||||
} else if (strchr("^%$0bBeEft", c)) {
|
||||
// These cmds operate on char positions
|
||||
do_cmd(c); // execute movement cmd
|
||||
q = dot;
|
||||
@ -2931,6 +2961,7 @@ static void show_help(void)
|
||||
printf("\tNamed buffers with \"x\n");
|
||||
#endif /* BB_FEATURE_VI_YANKMARK */
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
printf("\tReadonly if vi is called as \"view\"\n");
|
||||
printf("\tReadonly with -R command line arg\n");
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
#ifdef BB_FEATURE_VI_SET
|
||||
@ -3111,6 +3142,7 @@ static void rawmode(void)
|
||||
term_vi = term_orig;
|
||||
term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's
|
||||
term_vi.c_iflag &= (~IXON & ~ICRNL);
|
||||
term_vi.c_oflag &= (~ONLCR);
|
||||
term_vi.c_cc[VMIN] = 1;
|
||||
term_vi.c_cc[VTIME] = 0;
|
||||
erase_char = term_vi.c_cc[VERASE];
|
||||
@ -3172,7 +3204,7 @@ static void cont_sig(int sig)
|
||||
//----- Come here when we get a Suspend signal -------------------
|
||||
static void suspend_sig(int sig)
|
||||
{
|
||||
place_cursor(rows, 0); // go to bottom of screen
|
||||
place_cursor(rows - 1, 0, FALSE); // go to bottom of screen
|
||||
clear_to_eol(); // Erase to end of line
|
||||
cookmode(); // terminal to "cooked"
|
||||
|
||||
@ -3181,7 +3213,7 @@ static void suspend_sig(int sig)
|
||||
kill(getpid(), SIGTSTP);
|
||||
}
|
||||
|
||||
//----- Come here when we get a signal --------------------
|
||||
//----- Come here when we get a signal ---------------------------
|
||||
static void catch_sig(int sig)
|
||||
{
|
||||
signal(SIGHUP, catch_sig);
|
||||
@ -3382,7 +3414,6 @@ static Byte get_one_char()
|
||||
return (c); // return the char, where ever it came from
|
||||
}
|
||||
|
||||
#if defined(BB_FEATURE_VI_SEARCH) || defined(BB_FEATURE_VI_COLON)
|
||||
static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
|
||||
{
|
||||
Byte buf[BUFSIZ];
|
||||
@ -3392,7 +3423,7 @@ static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
|
||||
|
||||
strcpy((char *) buf, (char *) prompt);
|
||||
*status_buffer = '\0'; // clear the status buffer
|
||||
place_cursor(rows - 1, 0); // go to Status line, bottom of screen
|
||||
place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen
|
||||
clear_to_eol(); // clear the line
|
||||
write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt
|
||||
|
||||
@ -3421,7 +3452,6 @@ static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
|
||||
obufp = (Byte *) strdup((char *) buf);
|
||||
return (obufp);
|
||||
}
|
||||
#endif /* BB_FEATURE_VI_SEARCH || BB_FEATURE_VI_COLON */
|
||||
|
||||
static int file_size(Byte * fn) // what is the byte size of "fn"
|
||||
{
|
||||
@ -3465,9 +3495,15 @@ static int file_insert(Byte * fn, Byte * p, int size)
|
||||
}
|
||||
|
||||
// see if we can open the file
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
if (vi_readonly == TRUE) goto fi1; // do not try write-mode
|
||||
#endif
|
||||
fd = open((char *) fn, O_RDWR); // assume read & write
|
||||
if (fd < 0) {
|
||||
// could not open for writing- maybe file is read only
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
fi1:
|
||||
#endif
|
||||
fd = open((char *) fn, O_RDONLY); // try read-only
|
||||
if (fd < 0) {
|
||||
psbs("\"%s\" %s", fn, "could not open file");
|
||||
@ -3534,46 +3570,91 @@ static int file_write(Byte * fn, Byte * first, Byte * last)
|
||||
//
|
||||
|
||||
//----- Move the cursor to row x col (count from 0, not 1) -------
|
||||
static void place_cursor(int row, int col)
|
||||
static void place_cursor(int row, int col, int opti)
|
||||
{
|
||||
Byte buf[30];
|
||||
char cm1[BUFSIZ];
|
||||
char *cm;
|
||||
int l;
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
char cm2[BUFSIZ];
|
||||
Byte *screenp;
|
||||
// char cm3[BUFSIZ];
|
||||
int Rrow= last_row;
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
|
||||
if (row < 0)
|
||||
row = 0;
|
||||
if (row >= rows)
|
||||
row = rows - 1;
|
||||
if (col < 0)
|
||||
col = 0;
|
||||
if (col >= columns)
|
||||
col = columns - 1;
|
||||
sprintf((char *) buf, "%c[%d;%dH", 0x1b, row + 1, col + 1);
|
||||
l = strlen((char *) buf);
|
||||
write(1, buf, l);
|
||||
memset(cm1, '\0', BUFSIZ - 1); // clear the buffer
|
||||
|
||||
if (row < 0) row = 0;
|
||||
if (row >= rows) row = rows - 1;
|
||||
if (col < 0) col = 0;
|
||||
if (col >= columns) col = columns - 1;
|
||||
|
||||
//----- 1. Try the standard terminal ESC sequence
|
||||
sprintf((char *) cm1, CMrc, row + 1, col + 1);
|
||||
cm= cm1;
|
||||
if (opti == FALSE) goto pc0;
|
||||
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
//----- find the minimum # of chars to move cursor -------------
|
||||
//----- 2. Try moving with discreet chars (Newline, [back]space, ...)
|
||||
memset(cm2, '\0', BUFSIZ - 1); // clear the buffer
|
||||
|
||||
// move to the correct row
|
||||
while (row < Rrow) {
|
||||
// the cursor has to move up
|
||||
strcat(cm2, CMup);
|
||||
Rrow--;
|
||||
}
|
||||
while (row > Rrow) {
|
||||
// the cursor has to move down
|
||||
strcat(cm2, CMdown);
|
||||
Rrow++;
|
||||
}
|
||||
|
||||
// now move to the correct column
|
||||
strcat(cm2, "\r"); // start at col 0
|
||||
// just send out orignal source char to get to correct place
|
||||
screenp = &screen[row * columns]; // start of screen line
|
||||
strncat(cm2, screenp, col);
|
||||
|
||||
//----- 3. Try some other way of moving cursor
|
||||
//---------------------------------------------
|
||||
|
||||
// pick the shortest cursor motion to send out
|
||||
cm= cm1;
|
||||
if (strlen(cm2) < strlen(cm)) {
|
||||
cm= cm2;
|
||||
} /* else if (strlen(cm3) < strlen(cm)) {
|
||||
cm= cm3;
|
||||
} */
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
pc0:
|
||||
l= strlen(cm);
|
||||
if (l) write(1, cm, l); // move the cursor
|
||||
}
|
||||
|
||||
//----- Erase from cursor to end of line -----------------------
|
||||
static void clear_to_eol()
|
||||
{
|
||||
write(1, "\033[0K", 4); // Erase from cursor to end of line
|
||||
write(1, Ceol, strlen(Ceol)); // Erase from cursor to end of line
|
||||
}
|
||||
|
||||
//----- Erase from cursor to end of screen -----------------------
|
||||
static void clear_to_eos()
|
||||
{
|
||||
write(1, "\033[0J", 4); // Erase from cursor to end of screen
|
||||
write(1, Ceos, strlen(Ceos)); // Erase from cursor to end of screen
|
||||
}
|
||||
|
||||
//----- Start standout mode ------------------------------------
|
||||
static void standout_start() // send "start reverse video" sequence
|
||||
{
|
||||
write(1, "\033[7m", 4); // Start reverse video mode
|
||||
write(1, SOs, strlen(SOs)); // Start reverse video mode
|
||||
}
|
||||
|
||||
//----- End standout mode --------------------------------------
|
||||
static void standout_end() // send "end reverse video" sequence
|
||||
{
|
||||
write(1, "\033[0m", 4); // End reverse video mode
|
||||
write(1, SOn, strlen(SOn)); // End reverse video mode
|
||||
}
|
||||
|
||||
//----- Flash the screen --------------------------------------
|
||||
@ -3588,7 +3669,7 @@ static void flash(int h)
|
||||
|
||||
static void beep()
|
||||
{
|
||||
write(1, "\007", 1); // send out a bell character
|
||||
write(1, bell, strlen(bell)); // send out a bell character
|
||||
}
|
||||
|
||||
static void indicate_error(char c)
|
||||
@ -3608,25 +3689,25 @@ static void indicate_error(char c)
|
||||
//----- Erase the Screen[] memory ------------------------------
|
||||
static void screen_erase()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < screensize; i++) {
|
||||
screen[i] = '\0';
|
||||
}
|
||||
memset(screen, ' ', screensize); // clear new screen
|
||||
}
|
||||
|
||||
//----- Draw the status line at bottom of the screen -------------
|
||||
static void show_status_line(void)
|
||||
{
|
||||
int cnt;
|
||||
static int last_cksum;
|
||||
int l, cnt, cksum;
|
||||
|
||||
cnt = strlen((char *) status_buffer);
|
||||
place_cursor(rows - 1, 0); // put cursor on status line
|
||||
if (cnt > 0) {
|
||||
for (cksum= l= 0; l < cnt; l++) { cksum += (int)(status_buffer[l]); }
|
||||
// don't write the status line unless it changes
|
||||
if (cnt > 0 && last_cksum != cksum) {
|
||||
last_cksum= cksum; // remember if we have seen this line
|
||||
place_cursor(rows - 1, 0, FALSE); // put cursor on status line
|
||||
write(1, status_buffer, cnt);
|
||||
}
|
||||
clear_to_eol();
|
||||
place_cursor(crow, ccol); // put cursor back in correct place
|
||||
place_cursor(crow, ccol, FALSE); // put cursor back in correct place
|
||||
}
|
||||
}
|
||||
|
||||
//----- format the status buffer, the bottom line of screen ------
|
||||
@ -3636,10 +3717,10 @@ static void psbs(char *format, ...)
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
strcpy((char *) status_buffer, "\033[7m"); // Terminal standout mode on
|
||||
strcpy((char *) status_buffer, SOs); // Terminal standout mode on
|
||||
vsprintf((char *) status_buffer + strlen((char *) status_buffer), format,
|
||||
args);
|
||||
strcat((char *) status_buffer, "\033[0m"); // Terminal standout mode off
|
||||
strcat((char *) status_buffer, SOn); // Terminal standout mode off
|
||||
va_end(args);
|
||||
|
||||
return;
|
||||
@ -3686,7 +3767,7 @@ static void edit_status(void) // show file status on status line
|
||||
"%s line %d of %d --%d%%--",
|
||||
(cfn != 0 ? (char *) cfn : "No file"),
|
||||
#ifdef BB_FEATURE_VI_READONLY
|
||||
(readonly == TRUE ? " [Read only]" : ""),
|
||||
((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""),
|
||||
#endif /* BB_FEATURE_VI_READONLY */
|
||||
(file_modified == TRUE ? " [modified]" : ""),
|
||||
cur, tot, percent);
|
||||
@ -3695,12 +3776,50 @@ static void edit_status(void) // show file status on status line
|
||||
//----- Force refresh of all Lines -----------------------------
|
||||
static void redraw(int full_screen)
|
||||
{
|
||||
place_cursor(0, 0); // put cursor in correct place
|
||||
place_cursor(0, 0, FALSE); // put cursor in correct place
|
||||
clear_to_eos(); // tel terminal to erase display
|
||||
screen_erase(); // erase the internal screen buffer
|
||||
refresh(full_screen); // this will redraw the entire display
|
||||
}
|
||||
|
||||
//----- Format a text[] line into a buffer ---------------------
|
||||
static void format_line(Byte *dest, Byte *src, int li)
|
||||
{
|
||||
int co;
|
||||
Byte c;
|
||||
|
||||
for (co= 0; co < MAX_SCR_COLS; co++) {
|
||||
c= ' '; // assume blank
|
||||
if (li > 0 && co == 0) {
|
||||
c = '~'; // not first line, assume Tilde
|
||||
}
|
||||
// are there chars in text[] and have we gone past the end
|
||||
if (text < end && src < end) {
|
||||
c = *src++;
|
||||
}
|
||||
if (c == '\n')
|
||||
break;
|
||||
if (c < ' ' || c > '~') {
|
||||
if (c == '\t') {
|
||||
c = ' ';
|
||||
// co % 8 != 7
|
||||
for (; (co % tabstop) != (tabstop - 1); co++) {
|
||||
dest[co] = c;
|
||||
}
|
||||
} else {
|
||||
dest[co++] = '^';
|
||||
c |= '@'; // make it visible
|
||||
c &= 0x7f; // get rid of hi bit
|
||||
}
|
||||
}
|
||||
// the co++ is done here so that the column will
|
||||
// not be overwritten when we blank-out the rest of line
|
||||
dest[co] = c;
|
||||
if (src >= end)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----- Refresh the changed screen lines -----------------------
|
||||
// Copy the source line from text[] into the buffer and note
|
||||
// if the current screenline is different from the new buffer.
|
||||
@ -3709,97 +3828,102 @@ static void redraw(int full_screen)
|
||||
static void refresh(int full_screen)
|
||||
{
|
||||
static int old_offset;
|
||||
int li, co, changed;
|
||||
Byte c, buf[MAX_SCR_COLS];
|
||||
int li, changed;
|
||||
Byte buf[MAX_SCR_COLS];
|
||||
Byte *tp, *sp; // pointer into text[] and screen[]
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
int last_li= -2; // last line that changed- for optimizing cursor movement
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
|
||||
#ifdef BB_FEATURE_VI_WIN_RESIZE
|
||||
window_size_get(0);
|
||||
#endif /* BB_FEATURE_VI_WIN_RESIZE */
|
||||
sync_cursor(dot, &crow, &ccol);
|
||||
sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot")
|
||||
tp = screenbegin; // index into text[] of top line
|
||||
|
||||
// compare text[] to screen[] and mark screen[] lines that need updating
|
||||
for (li = 0; li < rows - 1; li++) {
|
||||
// format current text line into buf with "columns" wide
|
||||
for (co = 0; co < columns + offset;) {
|
||||
c = ' '; // assume blank
|
||||
if (li > 0 && co == 0) {
|
||||
c = '~'; // not first line, assume Tilde
|
||||
}
|
||||
// are there chars in text[]
|
||||
// and have we gone past the end
|
||||
if (text < end && tp < end) {
|
||||
c = *tp++;
|
||||
}
|
||||
if (c == '\n')
|
||||
break;
|
||||
if (c < ' ' || c > '~') {
|
||||
if (c == '\t') {
|
||||
c = ' ';
|
||||
// co % 8 != 7
|
||||
for (; (co % tabstop) != (tabstop - 1); co++) {
|
||||
buf[co] = c;
|
||||
}
|
||||
} else {
|
||||
buf[co++] = '^';
|
||||
c |= '@'; // make it visible
|
||||
c &= 0x7f; // get rid of hi bit
|
||||
}
|
||||
}
|
||||
// the co++ is done here so that the column will
|
||||
// not be overwritten when we blank-out the rest of line
|
||||
buf[co++] = c;
|
||||
if (tp >= end)
|
||||
break;
|
||||
}
|
||||
if (co >= columns + offset) {
|
||||
int cs, ce; // column start & end
|
||||
memset(buf, ' ', MAX_SCR_COLS); // blank-out the buffer
|
||||
buf[MAX_SCR_COLS-1] = 0; // NULL terminate the buffer
|
||||
// format current text line into buf
|
||||
format_line(buf, tp, li);
|
||||
|
||||
// skip to the end of the current text[] line
|
||||
while (tp < end && *tp++ != '\n');
|
||||
}
|
||||
// try to keep the cursor near it's current position
|
||||
// remember how many chars in this row- where the cursor sits
|
||||
// blank out the rest of the buffer
|
||||
while (co < MAX_SCR_COLS - 1) {
|
||||
buf[co++] = ' ';
|
||||
}
|
||||
buf[co++] = 0; // NULL terminate the buffer
|
||||
while (tp < end && *tp++ != '\n') /*no-op*/ ;
|
||||
|
||||
// if necessary, update virtual screen[] and terminal from buf[]
|
||||
// see if there are any changes between vitual screen and buf
|
||||
changed = FALSE; // assume no change
|
||||
cs= 0;
|
||||
ce= columns-1;
|
||||
sp = &screen[li * columns]; // start of screen line
|
||||
for (co = 0; co < columns; co++) {
|
||||
if (sp[co] != buf[co + offset]) {
|
||||
sp[co] = buf[co + offset];
|
||||
if (full_screen == TRUE) {
|
||||
// force re-draw of every single column from 0 - columns-1
|
||||
goto re0;
|
||||
}
|
||||
// compare newly formatted buffer with virtual screen
|
||||
// look forward for first difference between buf and screen
|
||||
for ( ; cs <= ce; cs++) {
|
||||
if (buf[cs + offset] != sp[cs]) {
|
||||
changed = TRUE; // mark for redraw
|
||||
}
|
||||
}
|
||||
// if horz offset has changed, force a redraw
|
||||
if (offset != old_offset)
|
||||
changed = TRUE;
|
||||
|
||||
// write all marked screen lines out to terminal
|
||||
if (changed == TRUE) {
|
||||
place_cursor(li, 0); // put cursor in correct place
|
||||
clear_to_eol(); // Erase to end of line
|
||||
if (full_screen == FALSE) {
|
||||
// don't redraw every column on terminal
|
||||
// look backwards for last non-blank
|
||||
for (co = columns + offset; co >= 0; co--) {
|
||||
// break;
|
||||
if (buf[co] != ' ')
|
||||
break;
|
||||
}
|
||||
co++;
|
||||
} else {
|
||||
// redraw every column on terminal
|
||||
co = columns;
|
||||
}
|
||||
|
||||
// look backward for last difference between buf and screen
|
||||
for ( ; ce >= cs; ce--) {
|
||||
if (buf[ce + offset] != sp[ce]) {
|
||||
changed = TRUE; // mark for redraw
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now, cs is index of first diff, and ce is index of last diff
|
||||
|
||||
// if horz offset has changed, force a redraw
|
||||
if (offset != old_offset) {
|
||||
re0:
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
// make a sanity check of columns indexes
|
||||
if (cs < 0) cs= 0;
|
||||
if (ce > columns-1) ce= columns-1;
|
||||
if (cs > ce) { cs= 0; ce= columns-1; }
|
||||
// is there a change between vitual screen and buf
|
||||
if (changed == TRUE) {
|
||||
// copy changed part of buffer to virtual screen
|
||||
memmove(sp+cs, buf+(cs+offset), ce-cs+1);
|
||||
|
||||
// move cursor to column of first change
|
||||
if (offset != old_offset) {
|
||||
// opti_cur_move is still too stupid
|
||||
// to handle offsets correctly
|
||||
place_cursor(li, cs, FALSE);
|
||||
} else {
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
// if this just the next line
|
||||
// try to optimize cursor movement
|
||||
// otherwise, use standard ESC sequence
|
||||
place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE);
|
||||
last_li= li;
|
||||
#else /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
place_cursor(li, cs, FALSE); // use standard ESC sequence
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
}
|
||||
|
||||
// write line out to terminal
|
||||
write(1, buf + offset, co);
|
||||
write(1, sp+cs, ce-cs+1);
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
last_row = li;
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
}
|
||||
}
|
||||
|
||||
place_cursor(crow, ccol);
|
||||
place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE);
|
||||
#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR
|
||||
last_row = crow;
|
||||
#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */
|
||||
|
||||
if (offset != old_offset)
|
||||
old_offset = offset;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user