/* vi:ts=4:sw=4 * * VIM - Vi IMproved * * Code Contributions By: Bram Moolenaar mool@oce.nl * Tim Thompson twitch!tjt * Tony Andrews onecom!wldrdg!tony * G. R. (Fred) Walter watmath!watcgl!grwalter */ /* * edit.c: functions for insert mode */ #include "vim.h" #include "globals.h" #include "proto.h" #include "param.h" #ifdef JP #include "jp.h" #endif #include "ops.h" /* for operator */ extern u_char *get_inserted(); static void start_arrow __ARGS((void)); static void stop_arrow __ARGS((void)); static void stop_insert __ARGS((void)); static int echeck_abbr __ARGS((int)); int arrow_used; /* Normally FALSE, set to TRUE after hitting * cursor key in insert mode. Used by vgetorpeek() * to decide when to call u_sync() */ int restart_edit = 0; /* call edit when next command finished */ static u_char *last_insert = NULL; /* the text of the previous insert */ static int last_insert_skip; /* number of chars in front of the previous insert */ static int new_insert_skip; /* number of chars in front of the current insert */ void edit(count) long count; { u_char c; #ifdef JP u_char k; #endif u_char cc; u_char *ptr; u_char *saved_line = NULL; /* saved line for replace mode */ linenr_t saved_lnum = 0; /* lnum of saved line */ u_char saved_char = NUL; /* char replaced by NL */ #ifdef JP u_char saved_kchar = NUL; #endif linenr_t lnum; int temp = 0; int mode; int nextc = 0; int lastc = 0; colnr_t mincol; if (restart_edit) { arrow_used = TRUE; restart_edit = 0; } else { arrow_used = FALSE; #ifdef JPFEP switch(*p_ji) { case 'J': KanjiInput = TRUE; goto modeset; case 'A': KanjiInput = FALSE; modeset: fep_mode_switch(KanjiInput); showmode(); } #endif #ifdef FEPCTRL switch(*p_ji) { case 'J': fep_force_on(); break; case 'A': fep_force_off(); break; } #endif } #ifdef DIGRAPHS dodigraph(-1); /* clear digraphs */ #endif /* * Get the current length of the redo buffer, those characters have to be * skipped if we want to get to the inserted characters. */ ptr = get_inserted(); new_insert_skip = strlen((char *)ptr); free(ptr); old_indent = 0; for (;;) { if (arrow_used) /* don't repeat insert when arrow key used */ count = 0; set_want_col = TRUE; /* set Curswant in case of K_DARROW or K_UARROW */ cursupdate(); /* Figure out where the cursor is based on Curpos. */ showruler(0); setcursor(); if (nextc) /* character remaining from CTRL-V */ { c = nextc; nextc = 0; } else { #ifdef JP jp_getchar(&c, &k, saved_line); #else c = vgetc(); #endif #ifdef FEPCTRL if (p_fc) #endif #if defined(JPFEP) || defined(FEPCTRL) if (p_ja && isupper(*p_ji)) { static int knj_asc = 0; /* for automatic change of p_ji */ char ji; ji = *p_ji; if (IsKanji(c)) { if (knj_asc > p_ja) ji = 'J'; else knj_asc ++; } else if (c > ' ') { if (knj_asc < - p_ja) ji = 'A'; else knj_asc --; } if (ji != *p_ji && isupper(*p_ji)) { *p_ji = ji; showmode(); } } #endif if (c == Ctrl('C') && got_int) got_int = FALSE; } if (c != Ctrl('D')) /* remember to detect ^^D and 0^D */ lastc = c; /* * In replace mode a backspace puts the original text back. * We save the current line to be able to do that. * If characters are appended to the line, they will be deleted. * If we start a new line (with CR) the saved line will be empty, thus * the characters will be deleted. * If we backspace over the new line, that line will be saved. */ if (State == REPLACE && saved_lnum != Curpos.lnum) { free(saved_line); saved_line = (u_char *)strsave((char *)nr2ptr(Curpos.lnum)); saved_lnum = Curpos.lnum; } #ifdef DIGRAPHS c = dodigraph(c); #endif /* DIGRAPHS */ if (c == Ctrl('V')) { outchar('^'); AppendToRedobuff("\026"); /* CTRL-V */ cursupdate(); setcursor(); #ifdef JP get_literal(&nextc, &c, &k); #else c = get_literal(&nextc); #endif /* erase the '^' */ if ((cc = gcharCurpos()) == NUL || (cc == TAB && !p_list)) outchar(' '); else outstrn(transchar(cc)); if (isidchar(c) || !echeck_abbr(c)) #ifdef JP insertchar(c, k); #else insertchar(c); #endif continue; } #ifdef DOSGEN /* may be used for UNIX */ if (c == Ctrl(']')) { #ifdef JP jp_getchar(&c, &k, saved_line); #else c = vgetc(); #endif switch (c) { case 'h': c = K_LARROW; break; case 'j': c = K_DARROW; break; case 'k': c = K_UARROW; break; case 'l': c = K_RARROW; break; case 'H': case 'b': c = K_SLARROW; break; case 'J': case Ctrl('F'): c = K_SDARROW; break; case 'K': case Ctrl('B'): c = K_SUARROW; break; case 'L': case 'w': c = K_SRARROW; break; default: beep(); continue; } } #endif switch (c) /* handle character in insert mode */ { #ifdef JP case Ctrl('Q'): #ifdef JPFEP fep_mode_switch(KanjiInput = FALSE); showmode(); cursupdate(); setcursor(); updateline(); #endif #ifdef FEPCTRL fep_force_off(); #endif break; #endif case Ctrl('O'): /* execute one command */ if (echeck_abbr(Ctrl('O') + 0x100)) break; count = 0; if (State == INSERT) restart_edit = 'I'; else restart_edit = 'R'; goto doESCkey; case ESC: /* an escape ends input mode */ if (echeck_abbr(ESC + 0x100)) break; /*FALLTHROUGH*/ case Ctrl('C'): doESCkey: if (!arrow_used) { AppendToRedobuff(ESC_STR); if (--count > 0) /* repeat what was typed */ { start_redo_ins(); continue; } stop_insert(); } set_want_col = TRUE; /* * The cursor should end up on the last inserted character. */ if (Curpos.col != 0 && (!restart_edit || gcharCurpos() == NUL) && !p_ri) decCurpos(); if (extraspace) /* did reverse replace in column 0 */ { delchar(FALSE); updateline(); extraspace = FALSE; } State = NORMAL; script_winsize_pp(); /* may need to put :winsize in script */ /* inchar() may have deleted the "INSERT" message */ if (Recording) showmode(); else if (p_smd) msg(""); free(saved_line); old_indent = 0; #ifdef JPFEP KanjiInput = fep_mode(); #endif return; /* * Insert the previously inserted text. * Last_insert actually is a copy of the redo buffer, so we * first have to remove the command. * For ^@ the trailing ESC will end the insert. */ #if !defined(JPFEP) && (!defined(MSDOS) || !defined(DOSGEN)) case K_ZERO: #endif case Ctrl('A'): stuff_inserted(NUL, 1L, (c == Ctrl('A'))); break; /* * insert the contents of a register */ case Ctrl('R'): if (!insertbuf(vgetc())) beep(); break; case Ctrl('P'): /* toggle reverse insert mode */ p_ri = !p_ri; showmode(); break; /* * If the cursor is on an indent, ^T/^D insert/delete one * shiftwidth. Otherwise ^T/^D behave like a TAB/backspace. * This isn't completely compatible with * vi, but the difference isn't very noticeable and now you can * mix ^D/backspace and ^T/TAB without thinking about which one * must be used. */ case Ctrl('T'): /* make indent one shiftwidth greater */ case Ctrl('D'): /* make indent one shiftwidth smaller */ stop_arrow(); AppendCharToRedobuff(c); if ((lastc == '0' || lastc == '^') && Curpos.col) { --Curpos.col; delchar(FALSE); /* delete the '^' or '0' */ if (lastc == '^') old_indent = get_indent(); /* remember current indent */ /* determine offset from first non-blank */ temp = Curpos.col; beginline(TRUE); temp -= Curpos.col; set_indent(0, TRUE); /* remove all indent */ } else { /* determine offset from first non-blank */ temp = Curpos.col; beginline(TRUE); temp -= Curpos.col; shift_line(c == Ctrl('D'), TRUE); /* try to put cursor on same character */ temp += Curpos.col; } if (temp <= 0) Curpos.col = 0; else Curpos.col = temp; did_ai = FALSE; did_si = FALSE; can_si = FALSE; goto redraw; case BS: case DEL: nextbs: mode = 0; dodel: /* can't delete anything in an empty file */ /* can't backup past first character in buffer */ /* can't backup past starting point unless 'backspace' > 1 */ /* can backup to a previous line if 'backspace' == 0 */ if (bufempty() || (!p_ri && ((Curpos.lnum == 1 && Curpos.col <= 0) || (p_bs < 2 && (arrow_used || (Curpos.lnum == Insstart.lnum && Curpos.col <= Insstart.col) || (Curpos.col <= 0 && p_bs == 0)))))) { beep(); goto redraw; } stop_arrow(); if (p_ri) incCurpos(); if (Curpos.col <= 0) /* delete newline! */ { lnum = Insstart.lnum; if (Curpos.lnum == Insstart.lnum || p_ri) { if (!u_save((linenr_t)(Curpos.lnum - 2), (linenr_t)(Curpos.lnum + 1))) goto redraw; --Insstart.lnum; Insstart.col = 0; } /* in replace mode, in the line we started replacing, we only move the cursor */ if (State != REPLACE || Curpos.lnum > lnum) { temp = gcharCurpos(); /* remember current char */ --Curpos.lnum; dojoin(FALSE, TRUE); if (temp == NUL && gcharCurpos() != NUL) #ifdef JP if (IsKanji(gcharCurpos())) Curpos.col += 2; else #endif ++Curpos.col; if (saved_char) /* restore what NL replaced */ { State = NORMAL; /* no replace for this char */ #ifdef JP inschar(saved_char, saved_kchar); /* but no showmatch */ #else inschar(saved_char); /* but no showmatch */ #endif State = REPLACE; saved_char = NUL; if (!p_ri) decCurpos(); } else if (p_ri) /* in reverse mode */ saved_lnum = 0; /* save this line again */ } else decCurpos(); did_ai = FALSE; } else { if (p_ri && State != REPLACE) decCurpos(); mincol = 0; if (mode == 3 && !p_ri && p_ai) /* keep indent */ { temp = Curpos.col; beginline(TRUE); if (Curpos.col < temp) mincol = Curpos.col; Curpos.col = temp; } /* delete upto starting point, start of line or previous word */ do { if (!p_ri) decCurpos(); /* start of word? */ if (mode == 1 && !isspace(gcharCurpos())) { mode = 2; temp = isidchar(gcharCurpos()); } /* end of word? */ else if (mode == 2 && (isspace(cc = gcharCurpos()) || isidchar(cc) != temp)) { if (!p_ri) incCurpos(); else if (State == REPLACE) decCurpos(); break; } if (State == REPLACE) { if (saved_line) { if (extraspace) { #ifdef JP char *s, *p; /* 1 for extraspace */ p = nr2ptr(Curpos.lnum) + 1; s = (char *)saved_line; while(*p && *s) { p += IsKanji(*p)? 2: 1; s += IsKanji(*s)? 2: 1; } if (*p) { if (IsKanji(gcharCurpos())) delchar(FALSE); delchar(FALSE); } else { decCurpos(); delchar(FALSE); extraspace = FALSE; if (IsKanji(gcharCurpos())) delchar(FALSE); delchar(FALSE); State = INSERT; insertchar(*(char *)saved_line, *((char *)saved_line + 1)); State = REPLACE; } #else if ((int)strlen(nr2ptr(Curpos.lnum)) - 1 > (int)strlen((char *)saved_line)) delchar(FALSE); else { decCurpos(); delchar(FALSE); extraspace = FALSE; pcharCurpos(*saved_line); } #endif } #ifdef JP else { char *p, *c, *s; p = nr2ptr(Curpos.lnum); c = p + Curpos.col; s = (char *)saved_line; while(p < c && *s) { p += IsKanji(*p) ? 2 : 1; s += IsKanji(*s) ? 2 : 1; } if (*s) { if (IsKanji(*p)) delchar(FALSE); delchar(FALSE); State = INSERT; insertchar(*s, *(s + 1)); State = REPLACE; if (!p_ri) decCurpos(); } else if (!p_ri) { if (IsKanji(gcharCurpos())) delchar(FALSE); delchar(FALSE); } } #else else if (Curpos.col < strlen((char *)saved_line)) pcharCurpos(saved_line[Curpos.col]); else if (!p_ri) delchar(FALSE); #endif } } else /* State != REPLACE */ { #ifdef JP if (IsKanji(gcharCurpos())) delchar(FALSE); #endif delchar(FALSE); if (p_ri && gcharCurpos() == NUL) break; } if (mode == 0) /* just a single backspace */ break; if (p_ri && State == REPLACE && incCurpos()) break; } while (p_ri || (Curpos.col > mincol && (Curpos.lnum != Insstart.lnum || Curpos.col != Insstart.col))); if (extraspace) decCurpos(); } did_si = FALSE; can_si = FALSE; if (Curpos.col <= 1) did_ai = FALSE; /* * It's a little strange to put backspaces into the redo * buffer, but it makes auto-indent a lot easier to deal * with. */ #ifdef JPFEP if (!KanjiInput) AppendCharToRedobuff(c); if (vpeekc() == BS && !KanjiInput) #else AppendCharToRedobuff(c); if (vpeekc() == BS) #endif { c = vgetc(); goto nextbs; /* speedup multiple backspaces */ } redraw: cursupdate(); updateline(); break; case Ctrl('W'): /* delete word before cursor */ mode = 1; goto dodel; case Ctrl('U'): /* delete inserted text in current line */ mode = 3; goto dodel; case Ctrl('B'): case K_LARROW: if (oneleft()) start_arrow(); else beep(); break; case K_SLARROW: if (Curpos.lnum > 1 || Curpos.col > 0) { bck_word(1L, 0); start_arrow(); } else beep(); break; case Ctrl('F'): case K_RARROW: if (gcharCurpos() != NUL) { set_want_col = TRUE; start_arrow(); #ifdef JP if (IsKanji(gcharCurpos())) Curpos.col += 2; else #endif ++Curpos.col; } else beep(); break; case K_SRARROW: if (Curpos.lnum < line_count || gcharCurpos() != NUL) { fwd_word(1L, 0, 0); start_arrow(); } else beep(); break; case K_UARROW: if (oneup(1L)) start_arrow(); else beep(); break; case K_SUARROW: if (onepage(BACKWARD, 1L)) start_arrow(); else beep(); break; case Ctrl('N'): case K_DARROW: if (onedown(1L)) start_arrow(); else beep(); break; case K_SDARROW: if (onepage(FORWARD, 1L)) start_arrow(); else beep(); break; case TAB: if (echeck_abbr(TAB + 0x100)) break; if (!p_et || (p_ri && State == REPLACE)) goto normalchar; /* expand a tab into spaces */ stop_arrow(); did_ai = FALSE; did_si = FALSE; can_si = FALSE; temp = (int)p_ts - Curpos.col % (int)p_ts; inschar(' '); /* delete one char in replace mode */ while (--temp) insstr(" "); /* insstr does not delete chars */ AppendToRedobuff("\t"); goto redraw; case CR: case NL: if (echeck_abbr(c + 0x100)) break; stop_arrow(); if (State == REPLACE) { #ifdef JP char *cp; cp = Curpos2ptr(); saved_char = *cp ++; saved_kchar= *cp; delchar(FALSE); if (IsKanji(saved_char)) delchar(FALSE); #else saved_char = gcharCurpos(); delchar(FALSE); #endif } AppendToRedobuff(NL_STR); if (!Opencmd(FORWARD, TRUE, State == INSERT)) goto doESCkey; /* out of memory */ if (p_ri) { decCurpos(); if (State == REPLACE && Curpos.col > 0) decCurpos(); } break; #ifdef JPFEP case K_ZERO: /* start/stop kanji mode */ case Ctrl('\\'): /* ^space or ^\ */ fep_mode_switch(KanjiInput = ! KanjiInput); showmode(); cursupdate(); setcursor(); updateline(); break; #endif /* JPFEP */ #ifdef FEPCTRL case K_ZERO: /* start/stop kanji mode */ case Ctrl('\\'): /* ^space or ^\ */ if (p_fc) { if (fep_get_mode()) fep_force_off(); else fep_force_on(); } break; #endif /* FEPCTRL */ #ifdef DIGRAPHS case Ctrl('K'): outchar('?'); AppendToRedobuff("\026"); /* CTRL-V */ setcursor(); c = vgetc(); outstrn(transchar(c)); setcursor(); c = getdigraph(c, vgetc()); goto normalchar; #endif /* DIGRAPHS */ case Ctrl('Y'): /* copy from previous line */ lnum = Curpos.lnum - 1; goto copychar; case Ctrl('E'): /* copy from next line */ lnum = Curpos.lnum + 1; copychar: if (lnum < 1 || lnum > line_count) { beep(); break; } /* try to advance to the cursor column */ temp = 0; ptr = (u_char *)nr2ptr(lnum); while (temp < Cursvcol && *ptr) #ifdef JP if (IsKanji(*ptr)) { temp += 2; ptr += 2; } else #endif temp += chartabsize(*ptr++, temp); if (temp > Cursvcol) #ifdef JP { --ptr; if (IsKanji(*ptr)) ptr --; } k = *(ptr + 1); #else --ptr; #endif if ((c = *ptr) == NUL) { beep(); break; } /*FALLTHROUGH*/ default: normalchar: if (Curpos.col > 0 && ((can_si && c == '}') || (did_si && c == '{'))) shift_line(TRUE, TRUE); if (isidchar(c) || !echeck_abbr(c)) #ifdef JP insertchar(c, k); #else insertchar(c); #endif break; } } } /* * Next character is interpreted literally. * A one, two or three digit decimal number is interpreted as its byte value. * If one or two digits are entered, *nextc is set to the next character. */ int #ifdef JP get_literal(nextc, cp, kp) int *nextc; char *cp, *kp; #else get_literal(nextc) int *nextc; #endif { u_char cc; u_char nc; int oldstate; int i; #ifndef JP char *cp; #endif oldstate = State; State = NOMAPPING; /* next characters not mapped */ if (got_int) { *nextc = NUL; #ifdef JP *cp = Ctrl('C'); #endif return Ctrl('C'); } cc = 0; for (i = 0; i < 3; ++i) { #ifdef JP jp_getchar(cp, kp, NULL); nc = *cp; if (IsKanji(nc)) break; #else nc = vgetc(); #endif if (!isdigit(nc)) break; cc = cc * 10 + nc - '0'; nc = 0; } if (i == 0) /* no number entered */ { cc = nc; nc = 0; if (cc == K_ZERO) /* NUL is stored as NL */ cc = '\n'; } #ifdef JP else if (IsKanji(cc) && cc & 0x60) cc &= 0x7f; #endif else if (cc == 0) /* NUL is stored as NL */ cc = '\n'; State = oldstate; *nextc = nc; got_int = FALSE; /* CTRL-C typed after CTRL-V is not an interrupt */ #ifdef JP *cp = cc; if (IsKanji(nc)) *nextc = 0; #endif return cc; } /* * Special characters in this context are those that need processing other * than the simple insertion that can be performed here. This includes ESC * which terminates the insert, and CR/NL which need special processing to * open up a new line. This routine tries to optimize insertions performed by * the "redo", "undo" or "put" commands, so it needs to know when it should * stop and defer processing to the "normal" mechanism. */ #define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL) void #ifdef JP insertchar(c, k) u_char c, k; #else insertchar(c) u_char c; #endif { #ifdef ONEW extern int onew_noredraw; #endif int haveto_redraw = FALSE; stop_arrow(); /* * If the cursor is past 'textwidth' and we are inserting a non-space, * try to break the line in two or more pieces. If c == NUL then we have * been called to do formatting only. If p_tw == 0 it does nothing. */ #ifdef ONEW if (c == NUL || (!onew_noredraw && !isspace(c))) #else if (c == NUL || !isspace(c)) #endif { while (p_tw && Cursvcol >= p_tw) { int startcol; /* Cursor column at entry */ int wantcol; /* column at textwidth border */ int foundcol; /* column for start of word */ #ifdef JP colnr_t vcol2col(); int kborder = FALSE; #endif if ((startcol = Curpos.col) == 0) break; #ifdef JP Curpos.col = vcol2col(Curpos.lnum, p_tw); #else coladvance((int)p_tw); /* find column of textwidth border */ #endif wantcol = Curpos.col; Curpos.col = startcol - 1; foundcol = 0; while (Curpos.col > 0) /* find position to break at */ { #ifdef JP /* check the last byte of a multi-byte char. */ if (IsKanji(gcharCurpos())) { foundcol = Curpos.col + 1; if (Curpos.col < wantcol) break; Curpos.col -= 2; kborder = TRUE; continue; } #endif if (isspace(gcharCurpos())) { while (Curpos.col > 0 && isspace(gcharCurpos())) --Curpos.col; if (Curpos.col == 0) /* only spaces in front of text */ break; foundcol = Curpos.col + 1; if (Curpos.col < wantcol) break; } #ifdef JP else { if (kborder) { foundcol = Curpos.col + 1; if (Curpos.col < wantcol) break; kborder = FALSE; } --Curpos.col; } #else --Curpos.col; #endif } if (foundcol == 0) /* no spaces, cannot break line */ { Curpos.col = startcol; break; } Curpos.col = foundcol; /* put cursor after pos. to break line */ #ifdef JP /* KINSOKU syori */ if (foundcol == startcol) { if (!c || (IsKanji(c) ? isjppunc(c, k, TRUE) /* close punc. */ : isaspunc(c, TRUE)) ) break; } else if (foundcol < startcol) /* for closing symbols */ { char *ptr, n; n = *(ptr = Curpos2ptr()); if (IsKanji(n)) { if (isjppunc(n, *(ptr + 1), TRUE)) foundcol += 2; } else if (n && isaspunc(n, TRUE)) foundcol ++; Curpos.col = foundcol; } if (foundcol > 0) /* for opening symbols */ { char *ptr; ptr = Curpos2ptr() - 1; if (IsKanji(*ptr)) { ptr --; if (isjppunc(*ptr, *(ptr + 1), FALSE)) foundcol -= 2; } else if (isaspunc(*ptr, FALSE)) foundcol --; Curpos.col = foundcol; } #endif startcol -= foundcol; if (!Opencmd(FORWARD, FALSE, FALSE)) break; while (isspace(gcharCurpos()) && startcol) /* delete blanks */ { delchar(FALSE); --startcol; /* adjust cursor pos. */ } Curpos.col += startcol; curs_columns(FALSE); /* update Cursvcol */ haveto_redraw = TRUE; } if (c == NUL) /* formatting only */ #ifdef JP { if (haveto_redraw) updateScreen(NOT_VALID); else updateline(); return; } #else return; #endif if (haveto_redraw) { /* * If the cursor ended up just below the screen we scroll up here * to avoid a redraw of the whole screen in the most common cases. */ if (Curpos.lnum == Botline && !emptyrows) s_del(0, 1, TRUE); updateScreen(CURSUPD); } } did_ai = FALSE; did_si = FALSE; can_si = FALSE; /* * If there's any pending input, grab up to MAX_COLUMNS at once. * This speeds up normal text input considerably. */ #ifdef JPFEP # ifdef ONEW if (!KanjiInput && !p_oh && vpeekc() != NUL && State != REPLACE && !p_ri) # else if (!KanjiInput && vpeekc() != NUL && State != REPLACE && !p_ri) #endif #else if (vpeekc() != NUL && State != REPLACE && !p_ri) #endif { char p[MAX_COLUMNS + 1]; int i; p[0] = c; i = 1; #ifdef JP if (IsKanji(c)) p[i++] = k; #endif while ((c = vpeekc()) != NUL && !ISSPECIAL(c) && i < MAX_COLUMNS && (!p_tw || (Cursvcol += charsize(p[i - 1])) < p_tw) && !(!no_abbr && !isidchar(c) && isidchar(p[i - 1]))) p[i++] = vgetc(); p[i] = '\0'; insstr(p); AppendToRedobuff(p); } else { #ifdef JP inschar(c, k); #ifdef ONEW /* avoid to put candidates into redo buffer */ if (!onew_noredraw) #endif { AppendCharToRedobuff(c); if (IsKanji(c)) AppendCharToRedobuff(k); } #else inschar(c); AppendCharToRedobuff(c); #endif } #ifdef ONEW if (!onew_noredraw) #endif updateline(); } /* * start_arrow() is called when an arrow key is used in insert mode. * It resembles hitting the key. */ static void start_arrow() { if (!arrow_used) /* something has been inserted */ { AppendToRedobuff(ESC_STR); arrow_used = TRUE; /* this means we stopped the current insert */ stop_insert(); } } /* * stop_arrow() is called before a change is made in insert mode. * If an arrow key has been used, start a new insertion. */ static void stop_arrow() { if (arrow_used) { u_saveCurpos(); /* errors are ignored! */ Insstart = Curpos; /* new insertion starts here */ ResetRedobuff(); AppendToRedobuff("1i"); /* pretend we start an insertion */ arrow_used = FALSE; } } /* * do a few things to stop inserting */ static void stop_insert() { stop_redo_ins(); /* * save the inserted text for later redo with ^@ */ free(last_insert); last_insert = get_inserted(); last_insert_skip = new_insert_skip; /* * If we just did an auto-indent, truncate the line, and put * the cursor back. */ if (did_ai && !arrow_used) { *nr2ptr(Curpos.lnum) = NUL; canincrease(0); Curpos.col = 0; if (p_list) /* the deletion is only seen in list mode */ updateline(); } did_ai = FALSE; did_si = FALSE; can_si = FALSE; } /* * oneright oneleft onedown oneup * * Move one char {right,left,down,up}. Return TRUE when sucessful, FALSE when * we hit a boundary (of a line, or the file). */ int oneright() { char *ptr; #ifdef JP char c; #endif ptr = Curpos2ptr(); set_want_col = TRUE; #ifdef JP c = *ptr; #endif if (*ptr++ == NUL || *ptr == NUL) return FALSE; #ifdef JP if (IsKanji(c)) { if (* ++ptr == NUL) return FALSE; Curpos.col += 2; } else #endif ++Curpos.col; return TRUE; } int oneleft() { set_want_col = TRUE; if (Curpos.col == 0) return FALSE; --Curpos.col; #ifdef JP { char *ptr; ptr = pos2ptr(&Curpos); if (IsKanji(*ptr)) --Curpos.col; } #endif return TRUE; } void beginline(flag) int flag; { Curpos.col = 0; if (flag) { register u_char *ptr; for (ptr = (u_char *)nr2ptr(Curpos.lnum); isspace(*ptr); ++ptr) ++Curpos.col; } set_want_col = TRUE; } int oneup(n) long n; { if (n != 0 && Curpos.lnum == 1) return FALSE; if (n >= Curpos.lnum) Curpos.lnum = 1; else Curpos.lnum -= n; if (operator == NOP) cursupdate(); /* make sure Topline is valid */ /* try to advance to the column we want to be at */ coladvance(Curswant); return TRUE; } int onedown(n) long n; { if (n != 0 && Curpos.lnum == line_count) return FALSE; Curpos.lnum += n; if (Curpos.lnum > line_count) Curpos.lnum = line_count; if (operator == NOP) cursupdate(); /* make sure Topline is valid */ /* try to advance to the column we want to be at */ coladvance(Curswant); return TRUE; } int onepage(dir, count) int dir; long count; { linenr_t lp; long n; if (line_count == 1) /* nothing to do */ return FALSE; for ( ; count > 0; --count) { if (dir == FORWARD ? (Topline >= line_count - 1) : (Topline == 1)) { beep(); return FALSE; } if (dir == FORWARD) { if (Botline > line_count) /* at end of file */ Topline = line_count; else if (plines(Botline) >= Rows - 3 || /* next line is big */ Botline - Topline <= 3) /* just three lines on screen */ Topline = Botline; else Topline = Botline - 2; Curpos.lnum = Topline; if (count != 1) comp_Botline(); } else /* dir == BACKWARDS */ { lp = Topline; /* * If the first two lines on the screen are not too big, we keep * them on the screen. */ if ((n = plines(lp)) > Rows / 2) --lp; else if (lp < line_count && n + plines(lp + 1) < Rows / 2) ++lp; Curpos.lnum = lp; n = 0; while (n <= Rows - 1 && lp >= 1) { n += plines(lp); --lp; } if (n <= Rows - 1) /* at begin of file */ Topline = 1; else if (lp >= Topline - 2) /* happens with very long lines */ { --Topline; comp_Botline(); Curpos.lnum = Botline - 1; } else Topline = lp + 2; } } beginline(TRUE); updateScreen(VALID); return TRUE; } void stuff_inserted(c, count, no_esc) int c; long count; int no_esc; { u_char *esc_ptr = NULL; u_char *ptr; if (last_insert == NULL) { emsg("No inserted text yet"); return; } if (c) stuffcharReadbuff(c); if (no_esc && (esc_ptr = (u_char *)strrchr((char *)last_insert, 27)) != NULL) *esc_ptr = NUL; /* remove the ESC */ /* skip the command */ ptr = last_insert + last_insert_skip; do stuffReadbuff((char *)ptr); while (--count > 0); if (no_esc && esc_ptr) *esc_ptr = 27; /* put the ESC back */ } /* * Check the word in front of the cursor for an abbreviation. * Called when the non-id character "c" has been entered. * When an abbreviation is recognized it is removed from the text and * the replacement string is inserted in typestr, followed by "c". */ static int echeck_abbr(c) int c; { if (p_paste || no_abbr) /* no abbreviations or in paste mode */ return FALSE; return check_abbr(c, nr2ptr(Curpos.lnum), Curpos.col, Curpos.lnum == Insstart.lnum ? Insstart.col : 0); }