/* * Read a line from the echo area, with single character prompt c. * A return value of 1 means the user blewit or blewit away. */ int readecho(int c) { register char *sc = cursor; void (*OP)(); bool waste; register int OPeek; if (WBOT == WECHO) vclean(); else vclrech(0); splitw++; vgoto(WECHO, 0); ex_putchar(c); vclreol(); vgoto(WECHO, 1); cursor = linebuf; linebuf[0] = 0; genbuf[0] = c; if (peekbr()) { if (!INS[0] || (INS[0] & (OVERBUF|TRIM)) == OVERBUF) goto blewit; vglobp = INS; } OP = Pline; Pline = normline; ignore(vgetline(0, genbuf + 1, &waste, c)); if (Outchar == termchar) ex_putchar('\n'); vscrap(); Pline = OP; if (Peekkey != ATTN && Peekkey != QUIT && Peekkey != CTRL('h')) { cursor = sc; vclreol(); return (0); } blewit: OPeek = Peekkey==CTRL('h') ? 0 : Peekkey; Peekkey = 0; splitw = 0; vclean(); vshow(dot, NOLINE); vnline(sc); Peekkey = OPeek; return (1); }
/* * Logically open up after line l, cnt of them. * We need to know if it was done ``physically'' since in this * case we accept what the hardware gives us. If we have to do * it ourselves (brute force) we will squish out @ lines in the process * if this will save us work. */ void vopenup(int cnt, int could, int l) { register struct vlinfo *vc = &vlinfo[l + 1]; register struct vlinfo *ve = &vlinfo[vcnt]; #ifdef ADEBUG if (trace) tfixnl(), fprintf(trace, "vopenup(%d, %d, %d)\n", cnt, could, l); #endif if (could) /* * This will push @ lines down the screen, * just as the hardware did. Since the default * for intelligent terminals is to never have @ * lines on the screen, this should never happen, * and the code makes no special effort to be nice in this * case, e.g. squishing out the @ lines by delete lines * before doing append lines. */ for (; vc <= ve; vc++) vc->vliny += cnt; else { /* * Will have to clean up brute force eventually, * so push the line data around as little as possible. */ vc->vliny += cnt, vc->vflags |= VDIRT; while (vc < ve) { register int i = vc->vliny + vc->vdepth; vc++; if (i <= vc->vliny) break; vc->vliny = i, vc->vflags |= VDIRT; } } vscrap(); }
void vappend(int ch, int cnt, int indent) { register int i; register char *gcursor; bool escape; int repcnt; short oldhold = hold; /* * Before a move in hardopen when the line is dirty * or we are in the middle of the printed representation, * we retype the line to the left of the cursor so the * insert looks clean. */ if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) { rubble = 1; wcursor = cursor; vmove(); } vaifirst = indent == 0; /* * Handle replace character by (eventually) * limiting the number of input characters allowed * in the vgetline routine. */ if (ch == 'r') repcnt = 2; else repcnt = 0; /* * If an autoindent is specified, then * generate a mixture of blanks to tabs to implement * it and place the cursor after the indent. * Text read by the vgetline routine will be placed in genbuf, * so the indent is generated there. */ if (value(AUTOINDENT) && indent != 0) { gcursor = genindent(indent); *gcursor = 0; vgotoCL(qcolumn(cursor - 1, genbuf)); } else { gcursor = genbuf; *gcursor = 0; if (ch == 'o') vfixcurs(); } /* * Prepare for undo. Pointers delimit inserted portion of line. */ vUA1 = vUA2 = cursor; /* * If we are not in a repeated command and a ^@ comes in * then this means the previous inserted text. * If there is none or it was too long to be saved, * then beep() and also arrange to undo any damage done * so far (e.g. if we are a change.) */ if ((vglobp && *vglobp == 0) || peekbr()) { if ((INS[0] & (OVERBUF|TRIM)) == OVERBUF) { beep(); if (!splitw) ungetkey('u'); doomed = 0; hold = oldhold; return; } /* * Unread input from INS. * An escape will be generated at end of string. * Hold off n^^2 type update on dumb terminals. */ vglobp = INS; hold |= HOLDQIK; } else if (vglobp == 0) /* * Not a repeated command, get * a new inserted text for repeat. */ INS[0] = 0; /* * For wrapmargin to hack away second space after a '.' * when the first space caused a line break we keep * track that this happened in gobblebl, which says * to gobble up a blank silently. */ gobblebl = 0; /* * Text gathering loop. * New text goes into genbuf starting at gcursor. * cursor preserves place in linebuf where text will eventually go. */ if (*cursor == 0 || state == CRTOPEN) hold |= HOLDROL; for (;;) { if (ch == 'r' && repcnt == 0) escape = 0; else { gcursor = vgetline(repcnt, gcursor, &escape); /* * After an append, stick information * about the ^D's and ^^D's and 0^D's in * the repeated text buffer so repeated * inserts of stuff indented with ^D as backtab's * can work. */ if (HADUP) addtext("^"); else if (HADZERO) addtext("0"); while (CDCNT > 0) addtext("\204"), CDCNT--; if (gobbled) addtext(" "); addtext(ogcursor); } repcnt = 0; /* * Smash the generated and preexisting indents together * and generate one cleanly made out of tabs and spaces * if we are using autoindent. */ if (!vaifirst && value(AUTOINDENT)) { i = fixindent(indent); if (!HADUP) indent = i; gcursor = strend(genbuf); } /* * Limit the repetition count based on maximum * possible line length; do output implied * by further count (> 1) and cons up the new line * in linebuf. */ cnt = vmaxrep(ch, cnt); CP(gcursor + 1, cursor); do { CP(cursor, genbuf); if (cnt > 1) { int oldhold = hold; Outchar = vinschar; hold |= HOLDQIK; ex_printf("%s", genbuf); hold = oldhold; Outchar = vputchar; } cursor += gcursor - genbuf; } while (--cnt > 0); endim(); vUA2 = cursor; if (escape != '\n') CP(cursor, gcursor + 1); /* * If doomed characters remain, clobber them, * and reopen the line to get the display exact. */ if (state != HARDOPEN) { DEPTH(vcline) = 0; if (doomed > 0) { register int cind = cindent(); physdc(cind, cind + doomed); doomed = 0; } i = vreopen(LINE(vcline), lineDOT(), vcline); } /* * All done unless we are continuing on to another line. */ if (escape != '\n') break; /* * Set up for the new line. * First save the current line, then construct a new * first image for the continuation line consisting * of any new autoindent plus the pushed ahead text. */ killU(); addtext(gobblebl ? " " : "\n"); vsave(); cnt = 1; if (value(AUTOINDENT)) { #ifdef LISP if (value(LISP)) indent = lindent(dot + 1); else #endif if (!HADUP && vaifirst) indent = whitecnt(linebuf); vaifirst = 0; strcLIN(vpastwh(gcursor + 1)); gcursor = genindent(indent); *gcursor = 0; if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2]) gcursor = genbuf; CP(gcursor, linebuf); } else { CP(genbuf, gcursor + 1); gcursor = genbuf; } /* * If we started out as a single line operation and are now * turning into a multi-line change, then we had better yank * out dot before it changes so that undo will work * correctly later. */ if (vundkind == VCHNG) { vremote(1, (void (*)(int))yank, 0); undap1--; } /* * Now do the append of the new line in the buffer, * and update the display. If slowopen * we don't do very much. */ vdoappend(genbuf); vundkind = VMANYINS; vcline++; if (state != VISUAL) vshow(dot, NOLINE); else { i += LINE(vcline - 1); vopen(dot, i); if (value(SLOWOPEN)) vscrap(); else vsync1(LINE(vcline)); } strcLIN(gcursor); *gcursor = 0; cursor = linebuf; vgotoCL(qcolumn(cursor - 1, genbuf)); } /* * All done with insertion, position the cursor * and sync the screen. */ hold = oldhold; if (cursor > linebuf) cursor--; if (state != HARDOPEN) vsyncCL(); else if (cursor > linebuf) back1(); doomed = 0; wcursor = cursor; vmove(); }
/* * The guts of a sync. Similar to redraw but * just less ambitous. */ void vsync1(register int p) { register int l; char temp[LBSIZE]; register struct vlinfo *vp = &vlinfo[0]; short oldhold = hold; #ifdef ADEBUG if (trace) tfixnl(), fprintf(trace, "vsync1(%d)\n", p), tvliny(); #endif if (holdupd) { if (holdupd < 3) holdupd = 2; return; } if (state == HARDOPEN || splitw) return; vscrap(); CP(temp, linebuf); if (vcnt == 0) LINE(0) = WTOP; l = 0; while (l < vcnt && vp->vliny < p) l++, vp++; heldech = 0; hold |= HOLDECH; while (p <= WBOT && Peekkey != ATTN) { /* * Want to put a line here if not in visual and first line * or if there are lies left and this line starts before * the current line, or if this line is piled under the * next line (vreplace does this and we undo it). */ if (l == 0 && state != VISUAL || (l < vcnt && (vp->vliny <= p || vp[0].vliny == vp[1].vliny))) { if (l == 0 || vp->vliny < p || (vp->vflags & VDIRT)) { if (l == vcline) strcLIN(temp); else getline(dot[l - vcline]); /* * Be careful that a long line doesn't cause the * screen to shoot up. */ if (l != vcline && (vp->vflags & VDIRT)) { vp->vdepth = vdepth(); vp->vflags &= ~VDIRT; if (p + vp->vdepth - 1 > WBOT) break; } vreopen(p, lineDOT() + (l - vcline), l); } p = vp->vliny + vp->vdepth; vp++; l++; } else /* * A physical line between logical lines, * so we settle for an @ at the beginning. */ vclrlin(p, dot + (l - vcline)), p++; } strcLIN(temp); hold = oldhold; if (heldech) vclrech(0); }
/* * Fully cleanup the screen, leaving no @ lines except at end when * line after last won't completely fit. The routine vsync is * more conservative and much less work on dumb terminals. */ void vredraw(register int p) { register int l; register line *tp; char temp[LBSIZE]; bool anydl = 0; short oldhold = hold; #ifdef ADEBUG if (trace) tfixnl(), fprintf(trace, "vredraw(%d)\n", p), tvliny(); #endif if (holdupd) { holdupd = 3; return; } if (state == HARDOPEN || splitw) return; if (p < 0 /* || p > WECHO */) error(catgets(catd, 1, 221, "Internal error: vredraw")); /* * Trim the ragged edges (lines which are off the screen but * not yet logically discarded), save the current line, and * search for first logical line affected by the redraw. */ vscrap(); CP(temp, linebuf); l = 0; tp = dot - vcline; if (vcnt == 0) LINE(0) = WTOP; while (l < vcnt && LINE(l) < p) l++, tp++; /* * We hold off echo area clearing during the redraw in deference * to a final clear of the echo area at the end if appropriate. */ heldech = 0; hold |= HOLDECH; for (; l < vcnt && Peekkey != ATTN; l++) { if (l == vcline) strcLIN(temp); else getline(*tp); /* * Delete junk between displayed lines. */ if (LINE(l) != LINE(l + 1) && LINE(l) != p) { if (anydl == 0 && DB && CD) { hold = oldhold; vclrech(0); anydl = 1; hold |= HOLDECH; heldech = 0; } vdellin(p, LINE(l) - p, l); } /* * If line image is not know to be up to date, then * redisplay it; else just skip onward. */ LINE(l) = p; if (FLAGS(l) & VDIRT) { DEPTH(l) = vdepth(); if (l != vcline && p + DEPTH(l) - 1 > WBOT) { vscrap(); break; } FLAGS(l) &= ~VDIRT; vreopen(p, lineno(tp), l); p = LINE(l) + DEPTH(l); } else p += DEPTH(l); tp++; } /* * That takes care of lines which were already partially displayed. * Now try to fill the rest of the screen with text. */ if (state == VISUAL && p <= WBOT) { int ovcline = vcline; vcline = l; for (; tp <= dol && Peekkey != ATTN; tp++) { getline(*tp); if (p + vdepth() - 1 > WBOT) break; vopen(tp, p); p += DEPTH(vcline); vcline++; } vcline = ovcline; } /* * Thats all the text we can get on. * Now rest of lines (if any) get either a ~ if they * are past end of file, or an @ if the next line won't fit. */ for (; p <= WBOT && Peekkey != ATTN; p++) vclrlin(p, tp); strcLIN(temp); hold = oldhold; if (heldech) vclrech(0); #ifdef ADEBUG if (trace) tvliny(); #endif }
/* * Repaint the screen, with cursor at curs, aftern an arbitrary change. * Handle notification on large changes. */ void vrepaint(char *curs) { wdot = NOLINE; /* * In open want to notify first. */ noteit(0); vscrap(); /* * Deal with a totally useless display. */ if (vcnt == 0 || vcline < 0 || vcline > vcnt || holdupd && state != VISUAL) { register line *odol = dol; vcnt = 0; if (holdupd) if (state == VISUAL) ignore(peekkey()); else vup1(); holdupd = 0; if (odol == zero) fixzero(); vcontext(dot, '.'); noteit(1); if (noteit(1) == 0 && odol == zero) { CATCH error(catgets(catd, 1, 220, "No lines in buffer")); ENDCATCH linebuf[0] = 0; splitw = 0; } vnline(curs); return; } /* * Have some useful displayed text; refresh it. */ getDOT(); /* * This is for boundary conditions in open mode. */ if (FLAGS(0) & VDIRT) vsync(WTOP); /* * If the current line is after the last displayed line * or the bottom of the screen, then special effort is needed * to get it on the screen. We first try a redraw at the * last line on the screen, hoping it will fill in where @ * lines are now. If this doesn't work, then roll it onto * the screen. */ if (vcline >= vcnt || LINE(vcline) > WBOT) { short oldhold = hold; hold |= HOLDAT, vredraw(LASTLINE), hold = oldhold; if (vcline >= vcnt) { register int i = vcline - vcnt + 1; dot -= i; vcline -= i; vroll(i); } else vsyncCL(); } else vsync(vcline > 0 ? LINE(vcline - 1) : WTOP); /* * Notification on large change for visual * has to be done last or we may lose * the echo area with redisplay. */ noteit(1); /* * Finally. Move the cursor onto the current line. */ vnline(curs); }
/* * Open new lines. * * Tricky thing here is slowopen. This causes display updating * to be held off so that 300 baud dumb terminals don't lose badly. * This also suppressed counts, which otherwise say how many blank * space to open up. Counts are also suppressed on intelligent terminals. * Actually counts are obsoleted, since if your terminal is slow * you are better off with slowopen. */ void voOpen ( int c, /* mjm: char --> int */ register int cnt ) { register int ind = 0, i; short oldhold = hold; #ifdef SIGWINCH sigset_t set, oset; #endif if (value(SLOWOPEN) || value(REDRAW) && AL && DL) cnt = 1; #ifdef SIGWINCH sigemptyset(&set); sigaddset(&set, SIGWINCH); sigprocmask(SIG_BLOCK, &set, &oset); #endif vsave(); setLAST(); if (value(AUTOINDENT)) ind = whitecnt(linebuf); if (c == 'O') { vcline--; dot--; if (dot > zero) getDOT(); } if (value(AUTOINDENT)) { #ifdef LISPCODE if (value(LISP)) ind = lindent(dot + 1); #endif } killU(); prepapp(); if (FIXUNDO) vundkind = VMANY; if (state != VISUAL) c = WBOT + 1; else { c = vcline < 0 ? WTOP - cnt : LINE(vcline) + DEPTH(vcline); if (c < ZERO) c = ZERO; i = LINE(vcline + 1) - c; if (i < cnt && c <= WBOT && (!AL || !DL)) vinslin(c, cnt - i, vcline); } *genindent(ind) = 0; vdoappend(genbuf); vcline++; oldhold = hold; hold |= HOLDROL; vopen(dot, c); hold = oldhold; if (value(SLOWOPEN)) /* * Oh, so lazy! */ vscrap(); else vsync1(LINE(vcline)); cursor = linebuf; linebuf[0] = 0; vappend('o', 1, ind); #ifdef SIGWINCH sigprocmask(SIG_SETMASK, &oset, NULL); #endif }
void vappend(int ch, int cnt, int indent) { int i; unsigned char *gcursor; bool escape; int repcnt, savedoomed; short oldhold = hold; int savecnt = cnt; line *startsrcline; int startsrccol, endsrccol; int gotNL = 0; int imultlinecnt = 0; int omultlinecnt = 0; if ((savecnt > 1) && (ch == 'o' || ch == 'O')) { omultlinecnt = 1; } #ifdef XPG6 if ((savecnt > 1) && (ch == 'a' || ch == 'A' || ch == 'i' || ch == 'I')) imultlinecnt = 1; #endif /* XPG6 */ /* * Before a move in hardopen when the line is dirty * or we are in the middle of the printed representation, * we retype the line to the left of the cursor so the * insert looks clean. */ if (ch != 'o' && state == HARDOPEN && (rubble || !ateopr())) { rubble = 1; gcursor = cursor; i = *gcursor; *gcursor = ' '; wcursor = gcursor; (void) vmove(); *gcursor = i; } /* * If vrep() passed indent = 0, this is the 'r' command, * so don't autoindent until the last char. */ vaifirst = indent == 0; /* * Handle replace character by (eventually) * limiting the number of input characters allowed * in the vgetline routine. */ if (ch == 'r') repcnt = 2; else repcnt = 0; /* * If an autoindent is specified, then * generate a mixture of blanks to tabs to implement * it and place the cursor after the indent. * Text read by the vgetline routine will be placed in genbuf, * so the indent is generated there. */ if (value(vi_AUTOINDENT) && indent != 0) { unsigned char x; gcursor = genindent(indent); *gcursor = 0; vgotoCL(nqcolumn(lastchr(linebuf, cursor), genbuf)); } else { gcursor = genbuf; *gcursor = 0; if (ch == 'o') vfixcurs(); } /* * Prepare for undo. Pointers delimit inserted portion of line. */ vUA1 = vUA2 = cursor; /* * If we are not in a repeated command and a ^@ comes in * then this means the previous inserted text. * If there is none or it was too long to be saved, * then beep() and also arrange to undo any damage done * so far (e.g. if we are a change.) */ switch (ch) { case 'r': break; case 'a': /* * TRANSLATION_NOTE * "A" is a terse mode message corresponding to * "APPEND MODE". * Translated message of "A" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("A")); } else { vshowmode(gettext("APPEND MODE")); } break; case 's': /* * TRANSLATION_NOTE * "S" is a terse mode message corresponding to * "SUBSTITUTE MODE". * Translated message of "S" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("S")); } else { vshowmode(gettext("SUBSTITUTE MODE")); } break; case 'c': /* * TRANSLATION_NOTE * "C" is a terse mode message corresponding to * "CHANGE MODE". * Translated message of "C" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("C")); } else { vshowmode(gettext("CHANGE MODE")); } break; case 'R': /* * TRANSLATION_NOTE * "R" is a terse mode message corresponding to * "REPLACE MODE". * Translated message of "R" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("R")); } else { vshowmode(gettext("REPLACE MODE")); } break; case 'o': /* * TRANSLATION_NOTE * "O" is a terse mode message corresponding to * "OPEN MODE". * Translated message of "O" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("O")); } else { vshowmode(gettext("OPEN MODE")); } break; case 'i': /* * TRANSLATION_NOTE * "I" is a terse mode message corresponding to * "INSERT MODE" and the following "INPUT MODE". * Translated message of "I" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("I")); } else { vshowmode(gettext("INSERT MODE")); } break; default: /* * TRANSLATION_NOTE * "I" is a terse mode message corresponding to * "INPUT MODE" and the previous "INSERT MODE". * Translated message of "I" must be 1 character (not byte). * Or, just leave it. */ if (value(vi_TERSE)) { vshowmode(gettext("I")); } else { vshowmode(gettext("INPUT MODE")); } } ixlatctl(1); if ((vglobp && *vglobp == 0) || peekbr()) { if (INS[128] == 0200) { (void) beep(); if (!splitw) ungetkey('u'); doomed = 0; hold = oldhold; return; } /* * Unread input from INS. * An escape will be generated at end of string. * Hold off n^^2 type update on dumb terminals. */ vglobp = INS; inscdcnt = INSCDCNT; hold |= HOLDQIK; } else if (vglobp == 0) { /* * Not a repeated command, get * a new inserted text for repeat. */ INS[0] = 0; INS[128] = 0; INSCDCNT = 0; } /* * For wrapmargin to hack away second space after a '.' * when the first space caused a line break we keep * track that this happened in gobblebl, which says * to gobble up a blank silently. */ gobblebl = 0; startsrcline = dot; startsrccol = cursor - linebuf; /* * Text gathering loop. * New text goes into genbuf starting at gcursor. * cursor preserves place in linebuf where text will eventually go. */ if (*cursor == 0 || state == CRTOPEN) hold |= HOLDROL; for (;;) { if (ch == 'r' && repcnt == 0) escape = 0; else { ixlatctl(1); /* * When vgetline() returns, gcursor is * pointing to '\0' and vgetline() has * read an ESCAPE or NL. */ gcursor = vgetline(repcnt, gcursor, &escape, ch); if (escape == '\n') { gotNL = 1; #ifdef XPG6 if (ch == 'r') { /* * XPG6 assertion 313 [count]r\n : * Arrange to set cursor correctly. */ endsrccol = gcursor - genbuf - 1; } #endif /* XPG6 */ } else { /* * Upon escape, gcursor is pointing to '\0' * terminating the string in genbuf. */ endsrccol = gcursor - genbuf - 1; } ixlatctl(0); /* * After an append, stick information * about the ^D's and ^^D's and 0^D's in * the repeated text buffer so repeated * inserts of stuff indented with ^D as backtab's * can work. */ if (HADUP) addtext("^"); else if (HADZERO) addtext("0"); if(!vglobp) INSCDCNT = CDCNT; while (CDCNT > 0) { addtext("\004"); CDCNT--; } if (gobbled) addtext(" "); addtext(ogcursor); } repcnt = 0; /* * Smash the generated and preexisting indents together * and generate one cleanly made out of tabs and spaces * if we are using autoindent and this isn't 'r' command. */ if (!vaifirst && value(vi_AUTOINDENT)) { i = fixindent(indent); if (!HADUP) indent = i; gcursor = strend(genbuf); } /* * Set cnt to 1 to avoid repeating the text on the same line. * Do this for commands 'i', 'I', 'a', and 'A', if we're * inserting anything with a newline for XPG6. Always do this * for commands 'o' and 'O'. */ if ((imultlinecnt && gotNL) || omultlinecnt) { cnt = 1; } /* * Limit the repetition count based on maximum * possible line length; do output implied * by further count (> 1) and cons up the new line * in linebuf. */ cnt = vmaxrep(ch, cnt); /* * cursor points to linebuf * Copy remaining old text (cursor) in original * line to after new text (gcursor + 1) in genbuf. */ CP(gcursor + 1, cursor); /* * For [count] r \n command, when replacing [count] chars * with '\n', this loop replaces [count] chars with "". */ do { /* cp new text (genbuf) into linebuf (cursor) */ CP(cursor, genbuf); if (cnt > 1) { int oldhold = hold; Outchar = vinschar; hold |= HOLDQIK; viprintf("%s", genbuf); hold = oldhold; Outchar = vputchar; } /* point cursor after new text in linebuf */ cursor += gcursor - genbuf; } while (--cnt > 0); endim(); vUA2 = cursor; /* add the remaining old text after the cursor */ if (escape != '\n') CP(cursor, gcursor + 1); /* * If doomed characters remain, clobber them, * and reopen the line to get the display exact. * eg. c$ to change to end of line */ if (state != HARDOPEN) { DEPTH(vcline) = 0; savedoomed = doomed; if (doomed > 0) { int cind = cindent(); physdc(cind, cind + doomed); doomed = 0; } if(MB_CUR_MAX > 1) rewrite = _ON; i = vreopen(LINE(vcline), lineDOT(), vcline); if(MB_CUR_MAX > 1) rewrite = _OFF; #ifdef TRACE if (trace) fprintf(trace, "restoring doomed from %d to %d\n", doomed, savedoomed); #endif if (ch == 'R') doomed = savedoomed; } /* * Unless we are continuing on to another line * (got a NL), break out of the for loop (got * an ESCAPE). */ if (escape != '\n') { vshowmode(""); break; } /* * Set up for the new line. * First save the current line, then construct a new * first image for the continuation line consisting * of any new autoindent plus the pushed ahead text. */ killU(); addtext(gobblebl ? " " : "\n"); /* save vutmp (for undo state) into temp file */ vsave(); cnt = 1; if (value(vi_AUTOINDENT)) { if (value(vi_LISP)) indent = lindent(dot + 1); else if (!HADUP && vaifirst) indent = whitecnt(linebuf); vaifirst = 0; strcLIN(vpastwh(gcursor + 1)); gcursor = genindent(indent); *gcursor = 0; if (gcursor + strlen(linebuf) > &genbuf[LBSIZE - 2]) gcursor = genbuf; CP(gcursor, linebuf); } else { /* * Put gcursor at start of genbuf to wipe * out previous line in preparation for * the next vgetline() loop. */ CP(genbuf, gcursor + 1); gcursor = genbuf; } /* * If we started out as a single line operation and are now * turning into a multi-line change, then we had better yank * out dot before it changes so that undo will work * correctly later. */ if (FIXUNDO && vundkind == VCHNG) { vremote(1, yank, 0); undap1--; } /* * Now do the append of the new line in the buffer, * and update the display, ie: append genbuf to * the file after dot. If slowopen * we don't do very much. */ vdoappend(genbuf); vundkind = VMANYINS; vcline++; if (state != VISUAL) vshow(dot, NOLINE); else { i += LINE(vcline - 1); vopen(dot, i); if (value(vi_SLOWOPEN)) vscrap(); else vsync1(LINE(vcline)); } switch (ch) { case 'r': break; case 'a': if (value(vi_TERSE)) { vshowmode(gettext("A")); } else { vshowmode(gettext("APPEND MODE")); } break; case 's': if (value(vi_TERSE)) { vshowmode(gettext("S")); } else { vshowmode(gettext("SUBSTITUTE MODE")); } break; case 'c': if (value(vi_TERSE)) { vshowmode(gettext("C")); } else { vshowmode(gettext("CHANGE MODE")); } break; case 'R': if (value(vi_TERSE)) { vshowmode(gettext("R")); } else { vshowmode(gettext("REPLACE MODE")); } break; case 'i': if (value(vi_TERSE)) { vshowmode(gettext("I")); } else { vshowmode(gettext("INSERT MODE")); } break; case 'o': if (value(vi_TERSE)) { vshowmode(gettext("O")); } else { vshowmode(gettext("OPEN MODE")); } break; default: if (value(vi_TERSE)) { vshowmode(gettext("I")); } else { vshowmode(gettext("INPUT MODE")); } } strcLIN(gcursor); /* zero genbuf */ *gcursor = 0; cursor = linebuf; vgotoCL(nqcolumn(cursor - 1, genbuf)); } /* end for (;;) loop in vappend() */ if (imultlinecnt && gotNL) { imultlinerep(savecnt, startsrcline, startsrccol, endsrccol); } else if (omultlinecnt) { omultlinerep(savecnt, startsrcline, endsrccol); #ifdef XPG6 } else if (savecnt > 1 && ch == 'r' && gotNL) { /* * XPG6 assertion 313 & 254 : Position cursor for [count]r\n * then insert [count -1] newlines. */ endsrccol = gcursor - genbuf - 1; rmultlinerep(savecnt, endsrccol); #endif /* XPG6 */ } /* * All done with insertion, position the cursor * and sync the screen. */ hold = oldhold; if ((imultlinecnt && gotNL) || omultlinecnt) { fixdisplay(); #ifdef XPG6 } else if (savecnt > 1 && ch == 'r' && gotNL) { fixdisplay(); /* * XPG6 assertion 313 & 254 [count]r\n : Set flag to call * fixdisplay() after operate() has finished. To be sure that * the text (after the last \n followed by an indent) is always * displayed, fixdisplay() is called right before getting * the next command. */ redisplay = 1; #endif /* XPG6 */ } else if (cursor > linebuf) { cursor = lastchr(linebuf, cursor); #ifdef XPG6 /* * XPG6 assertion 313 & 254 [count]r\n : * For 'r' command, when the replacement char causes new * lines to be created, point cursor to first non-blank. * The old code, ie: cursor = lastchr(linebuf, cursor); * set cursor to the blank before the first non-blank * for r\n */ if (ch == 'r' && gotNL && isblank((int)*cursor)) ++cursor; #endif /* XPG6 */ } if (state != HARDOPEN) vsyncCL(); else if (cursor > linebuf) back1(); doomed = 0; wcursor = cursor; (void) vmove(); }