void axes(void) { int i; if(gridf==0) return; line(xd.xbot,yd.xbot,xd.xtop,yd.xbot); cont(xd.xtop,yd.xtop); cont(xd.xbot,yd.xtop); cont(xd.xbot,yd.xbot); (void) setmark(&xd, 1); (void) setmark(&yd, 1); }
void setFaceMarker( std::vector<std::string> vecmark ) { M_listMarkers.clear(); std::set<std::string> setmark( vecmark.begin(), vecmark.end() ); for ( std::string const& mark : setmark ) M_listMarkers.push_back( mark ); }
/* * Go to the beginning of the * buffer. Setting WFFULL is conservative, * but almost always the case. */ int gotobob(int f, int n) { (void) setmark(f, n); curwp->w_dotp = bfirstlp(curbp); curwp->w_doto = 0; curwp->w_rflag |= WFFULL; curwp->w_dotline = 1; return (TRUE); }
/* * Go to the end of the buffer. * Setting WFFULL is conservative, but * almost always the case. */ int gotoeob(int f, int n) { (void) setmark(f, n); curwp->w_dotp = blastlp(curbp); curwp->w_doto = llength(curwp->w_dotp); curwp->w_dotline = curwp->w_bufp->b_lines; curwp->w_flag |= WFFULL; return (TRUE); }
static void jmpmark(int c, int offset) { if (c == '`') c = '\''; if (ISMARK(c) && mark[c]) { int dst = mark[c]; int dst_row = offset ? mark_row[c] * zoom : 0; setmark('\''); if (!loadpage(dst)) srow = offset ? dst_row : prow; } }
static void copydata(void) { char symbol[PATLEN + 1]; char *cp; setmark('\t'); cp = blockp; for (;;) { /* copy up to the next \t */ do { /* innermost loop optimized to only one test */ while (*cp != '\t') { dbputc(*cp++); } } while (*++cp == '\0' && (cp = readblock()) != NULL); dbputc('\t'); /* copy the tab */ /* get the next character */ if (*(cp + 1) == '\0') { cp = readblock(); } /* exit if at the end of this file's data */ if (cp == NULL || *cp == NEWFILE) { break; } /* look for an #included file */ if (*cp == INCLUDE) { blockp = cp; putinclude(symbol); putstring(symbol); setmark('\t'); cp = blockp; } } blockp = cp; }
/* * Go to the end of the buffer. Leave dot 3 lines from the bottom of the * window if buffer length is longer than window length; same as emacs. * Setting WFFULL is conservative, but almost always the case. */ int gotoeob(int f, int n) { struct line *lp; (void) setmark(f, n); curwp->w_dotp = blastlp(curbp); curwp->w_doto = llength(curwp->w_dotp); curwp->w_dotline = curwp->w_bufp->b_lines; lp = curwp->w_dotp; n = curwp->w_ntrows - 3; if (n < curwp->w_bufp->b_lines && n >= 3) { while (n--) curwp->w_dotp = lback(curwp->w_dotp); curwp->w_linep = curwp->w_dotp; curwp->w_dotp = lp; } curwp->w_rflag |= WFFULL; return (TRUE); }
/* * Fill the current paragraph according to the current fill column */ int fillpara(int f, int n) { UCS *qstr, qstr2[NSTRING], c; int quotelevel = -1; REGION addedregion; char action = 'P'; if(curbp->b_mode&MDVIEW){ /* don't allow this command if */ return(rdonly()); /* we are in read only mode */ } else if (fillcol == 0) { /* no fill column set */ mlwrite_utf8("No fill column set", NULL); return(FALSE); } else if(curwp->w_dotp == curbp->b_linep && !curwp->w_markp) /* don't wrap! */ return(FALSE); /* * If there is already a region set, then we may use it * instead of the current paragraph. */ if(curwp->w_markp){ int k, rv; KEYMENU menu_justify[12]; char prompt[100]; for(k = 0; k < 12; k++){ menu_justify[k].name = NULL; KS_OSDATASET(&menu_justify[k], KS_NONE); } menu_justify[1].name = "R"; menu_justify[1].label = "[" N_("Region") "]"; menu_justify[6].name = "^C"; menu_justify[6].label = N_("Cancel"); menu_justify[7].name = "P"; menu_justify[7].label = N_("Paragraph"); menu_justify[2].name = "Q"; menu_justify[2].label = N_("Quotelevel"); wkeyhelp(menu_justify); /* paint menu */ sgarbk = TRUE; if(Pmaster && curwp) curwp->w_flag |= WFMODE; strncpy(prompt, "justify Region, Paragraph; or fix Quotelevel ? ", sizeof(prompt)); prompt[sizeof(prompt)-1] = '\0'; mlwrite_utf8(prompt, NULL); (*term.t_rev)(1); rv = -1; while(1){ switch(c = GetKey()){ case (CTRL|'C') : /* Bail out! */ case F2 : pputs_utf8(_("ABORT"), 1); rv = ABORT; emlwrite("", NULL); break; case (CTRL|'M') : /* default */ case 'r' : case 'R' : case F3 : pputs_utf8(_("Region"), 1); rv = 'R'; break; case 'p' : case 'P' : case F7 : pputs_utf8(_("Paragraph"), 1); rv = 'P'; break; case 'q' : case 'Q' : case F8 : case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : pputs_utf8(_("Quotelevel"), 1); while(rv == -1){ switch(c){ case 'q' : case 'Q' : case F8 : {char num[20]; num[0] = '\0'; switch(mlreplyd_utf8("Quote Level ? ", num, sizeof(num), QNORML, NULL)){ case TRUE: if(isdigit(num[0])){ quotelevel = atoi(num); if(quotelevel < 0){ emlwrite("Quote Level cannot be negative", NULL); sleep(3); } else if(quotelevel > 20){ emlwrite("Quote Level should be less than 20", NULL); rv = ABORT; } else{ rv = 'Q'; } } else if(num[0]){ emlwrite("Quote Level should be a number", NULL); sleep(3); } break; case HELPCH: emlwrite("Enter the number of quotes you want before the text", NULL); sleep(3); break; default: emlwrite("Quote Level is a number", NULL); rv = ABORT; break; } } break; case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : rv = 'Q'; quotelevel = (int) (c - '0'); break; } } break; case (CTRL|'G') : if(term.t_mrow == 0 && km_popped == 0){ movecursor(term.t_nrow-2, 0); peeol(); term.t_mrow = 2; (*term.t_rev)(0); wkeyhelp(menu_justify); mlwrite_utf8(prompt, NULL); (*term.t_rev)(1); sgarbk = TRUE; /* mark menu dirty */ km_popped++; break; } /* else fall through */ default: (*term.t_beep)(); case NODATA : break; } (*term.t_flush)(); if(rv != -1){ (*term.t_rev)(0); if(km_popped){ term.t_mrow = 0; movecursor(term.t_nrow, 0); peeol(); sgarbf = 1; km_popped = 0; } action = rv; break; } } if(action != ABORT) emlwrite("", NULL); } if(action == 'R' && curwp->w_markp){ /* let yank() know that it may be restoring a paragraph */ thisflag |= CFFILL; if(!Pmaster) sgarbk = TRUE; curwp->w_flag |= WFMODE; swap_mark_and_dot_if_mark_comes_first(); /* determine if we're justifying quoted text or not */ qstr = (glo_quote_str && quote_match(glo_quote_str, curwp->w_doto > 0 ? curwp->w_dotp->l_fp : curwp->w_dotp, qstr2, NSTRING) && *qstr2) ? qstr2 : NULL; /* * Fillregion moves dot to the end of the filled region. */ if(!fillregion(qstr, &addedregion)) return(FALSE); set_last_region_added(&addedregion); } else if(action == 'P'){ /* * Justfiy the current paragraph. */ if(curwp->w_markp) /* clear mark if already set */ setmark(0,0); if(gotoeop(FALSE, 1) == FALSE) return(FALSE); /* determine if we're justifying quoted text or not */ qstr = (glo_quote_str && quote_match(glo_quote_str, curwp->w_dotp, qstr2, NSTRING) && *qstr2) ? qstr2 : NULL; setmark(0,0); /* mark last line of para */ /* jump back to the beginning of the paragraph */ gotobop(FALSE, 1); /* let yank() know that it may be restoring a paragraph */ thisflag |= (CFFILL | CFFLPA); if(!Pmaster) sgarbk = TRUE; curwp->w_flag |= WFMODE; curwp->w_doto = 0; /* start region at beginning of line */ /* * Fillregion moves dot to the end of the filled region. */ if(!fillregion(qstr, &addedregion)) return(FALSE); set_last_region_added(&addedregion); /* Leave cursor on first char of first line after justified region */ curwp->w_dotp = lforw(curwp->w_dotp); curwp->w_doto = 0; if(curwp->w_markp) setmark(0,0); /* clear mark */ } else if(action == 'Q'){ /* let yank() know that it may be restoring a paragraph */ thisflag |= CFFILL; if(!Pmaster) sgarbk = TRUE; curwp->w_flag |= WFHARD; swap_mark_and_dot_if_mark_comes_first(); if(!setquotelevelinregion(quotelevel, &addedregion)) return(FALSE); set_last_region_added(&addedregion); } else{ /* abort */ } return(TRUE); }
/* * Main command processor. * Accept and execute commands until a quit command, then return. */ void commands(void) { int c, action; last_mca = 0; nscroll = (sc_height + 1) / 2; for (;;) { mca = 0; number = 0; /* * See if any signals need processing. */ if (sigs) { psignals(); if (quitting) quit(); } /* * Display prompt and accept a character. */ CMD_RESET; if (!prompt()) { next_file(1); continue; } noprefix(); c = getcc(); again: if (sigs) continue; /* * If we are in a multicharacter command, call mca_char. * Otherwise we call cmd_decode to determine the * action to be performed. */ if (mca) switch (mca_char(c)) { case MCA_MORE: /* * Need another character. */ c = getcc(); goto again; case MCA_DONE: /* * Command has been handled by mca_char. * Start clean with a prompt. */ continue; case NO_MCA: /* * Not a multi-char command * (at least, not anymore). */ break; } /* decode the command character and decide what to do. */ switch (action = cmd_decode(c)) { case A_DIGIT: /* first digit of a number */ start_mca(A_DIGIT, ":"); goto again; case A_F_SCREEN: /* forward one screen */ CMD_EXEC; if (number <= 0 && (number = sc_window) <= 0) number = sc_height - 1; forward(number, 1); break; case A_B_SCREEN: /* backward one screen */ CMD_EXEC; if (number <= 0 && (number = sc_window) <= 0) number = sc_height - 1; backward(number, 1); break; case A_F_LINE: /* forward N (default 1) line */ CMD_EXEC; forward(number <= 0 ? 1 : number, 0); break; case A_B_LINE: /* backward N (default 1) line */ CMD_EXEC; backward(number <= 0 ? 1 : number, 0); break; case A_F_SCROLL: /* forward N lines */ CMD_EXEC; if (number > 0) nscroll = number; forward(nscroll, 0); break; case A_B_SCROLL: /* backward N lines */ CMD_EXEC; if (number > 0) nscroll = number; backward(nscroll, 0); break; case A_FREPAINT: /* flush buffers and repaint */ if (!ispipe) { ch_init(0, 0); clr_linenum(); } /* FALLTHROUGH */ case A_REPAINT: /* repaint the screen */ CMD_EXEC; repaint(); break; case A_GOLINE: /* go to line N, default 1 */ CMD_EXEC; if (number <= 0) number = 1; jump_back(number); break; case A_PERCENT: /* go to percent of file */ CMD_EXEC; if (number < 0) number = 0; else if (number > 100) number = 100; jump_percent(number); break; case A_GOEND: /* go to line N, default end */ CMD_EXEC; if (number <= 0) jump_forw(); else jump_back(number); break; case A_STAT: /* print file name, etc. */ longprompt = 1; continue; case A_QUIT: /* exit */ quit(); case A_F_SEARCH: /* search for a pattern */ case A_B_SEARCH: if (number <= 0) number = 1; start_mca(action, (action==A_F_SEARCH) ? "/" : "?"); last_mca = mca; wsearch = 1; c = getcc(); if (c == '!') { /* * Invert the sense of the search; set wsearch * to 0 and get a new character for the start * of the pattern. */ start_mca(action, (action == A_F_SEARCH) ? "!/" : "!?"); wsearch = 0; c = getcc(); } goto again; case A_AGAIN_SEARCH: /* repeat previous search */ if (number <= 0) number = 1; if (wsearch) start_mca(last_mca, (last_mca == A_F_SEARCH) ? "/" : "?"); else start_mca(last_mca, (last_mca == A_F_SEARCH) ? "!/" : "!?"); CMD_EXEC; (void)search(mca == A_F_SEARCH, (char *)NULL, number, wsearch); break; case A_HELP: /* help */ lower_left(); clear_eol(); fputs("help", stdout); CMD_EXEC; help(); break; case A_TAGFILE: /* tag a new file */ CMD_RESET; start_mca(A_TAGFILE, "Tag: "); c = getcc(); goto again; case A_FILE_LIST: /* show list of file names */ CMD_EXEC; showlist(); repaint(); break; case A_EXAMINE: /* edit a new file */ CMD_RESET; start_mca(A_EXAMINE, "Examine: "); c = getcc(); goto again; case A_VISUAL: /* invoke the editor */ if (ispipe) { error("Cannot edit standard input"); break; } CMD_EXEC; editfile(); ch_init(0, 0); clr_linenum(); break; case A_NEXT_FILE: /* examine next file */ if (number <= 0) number = 1; next_file(number); break; case A_PREV_FILE: /* examine previous file */ if (number <= 0) number = 1; prev_file(number); break; case A_SETMARK: /* set a mark */ lower_left(); clear_eol(); start_mca(A_SETMARK, "mark: "); c = getcc(); if (c == erase_char || c == kill_char) break; setmark(c); break; case A_GOMARK: /* go to mark */ lower_left(); clear_eol(); start_mca(A_GOMARK, "goto mark: "); c = getcc(); if (c == erase_char || c == kill_char) break; gomark(c); break; case A_PREFIX: /* * The command is incomplete (more chars are needed). * Display the current char so the user knows what's * going on and get another character. */ if (mca != A_PREFIX) start_mca(A_PREFIX, ""); if (CONTROL_CHAR(c)) { putchar('^'); c = CARAT_CHAR(c); } putchar(c); c = getcc(); goto again; default: putchar('\7'); break; } } }
void normal() { register u_char c; long n; int flag = FALSE; int type = 0; /* used in some operations to modify type */ int dir = FORWARD; /* search direction */ u_char nchar = NUL; int finish_op; linenr_t Prenum1; char searchbuff[CMDBUFFSIZE]; /* buffer for search string */ FPOS *pos; register char *ptr; int command_busy = FALSE; static linenr_t redo_Quote_nlines; static int redo_Quote_type; static long redo_Quote_col; Prenum = 0; /* * If there is an operator pending, then the command we take this time * will terminate it. Finish_op tells us to finish the operation before * returning this time (unless the operation was cancelled). */ finish_op = (operator != NOP); if (!finish_op && !yankbuffer) opnum = 0; if (vpeekc() == NUL || KeyTyped == TRUE) premsg(NUL, NUL); State = NORMAL_BUSY; c = vgetc(); /* Pick up any leading digits and compute 'Prenum' */ while ((c >= '1' && c <= '9') || (Prenum > 0 && (c == DEL || c == '0'))) { if (c == DEL) Prenum /= 10; else Prenum = Prenum * 10 + (c - '0'); premsg(' ', NUL); c = vgetc(); } /* * If we're in the middle of an operator (including after entering a yank * buffer with ") AND we had a count before the * operator, then that count overrides the current value of Prenum. What * this means effectively, is that commands like "3dw" get turned into * "d3w" which makes things fall into place pretty neatly. * If you give a count before AND after the operator, they are multiplied. */ if (opnum != 0) { if (Prenum) Prenum *= opnum; else Prenum = opnum; opnum = 0; } Prenum1 = (Prenum == 0 ? 1 : Prenum); /* Prenum often defaults to 1 */ premsg(c, NUL); /* * get an additional character if we need one */ if (strchr("@zZtTfF[]rm'`\"", c) || (c == 'v' && Recording == FALSE)) { State = NOMAPPING; nchar = vgetc(); /* no macro mapping for this char */ premsg(c, nchar); } flushbuf(); /* flush the premsg() characters onto the screen so we can see them while the command is being executed */ if (c != 'z') /* the 'z' command gets another character */ { State = NORMAL; script_winsize_pp(); } if (nchar == ESC) { CLEAROP; goto normal_end; } switch (c) { /* * 0: Macros */ case 'v': /* (stop) recording into a named buffer */ CHECKCLEAROP; if (!dorecord(nchar)) CLEAROPBEEP; break; case '@': /* execute a named buffer */ CHECKCLEAROP; while (Prenum1--) if (!doexecbuf(nchar)) { CLEAROPBEEP; break; } break; /* * 1: Screen positioning commands */ case CTRL('D'): flag = TRUE; case CTRL('U'): CHECKCLEAROP; if (Prenum) p_scroll = (Prenum > Rows - 1) ? Rows - 1 : Prenum; n = (p_scroll < Rows) ? p_scroll : Rows - 1; if (flag) { scrollup(n); onedown(n); } else { scrolldown(n); oneup(n); } updateScreen(VALID); break; case CTRL('B'): case K_SUARROW: dir = BACKWARD; case CTRL('F'): case K_SDARROW: CHECKCLEAROP; onepage(dir, Prenum1); break; case CTRL('E'): CHECKCLEAROP; scrollup(Prenum1); updateScreen(VALID); break; case CTRL('Y'): CHECKCLEAROP; scrolldown(Prenum1); updateScreen(VALID); break; case 'z': CHECKCLEAROP; if (isdigit(nchar)) { /* * we misuse some variables to be able to call premsg() */ operator = c; opnum = Prenum; Prenum = nchar - '0'; for (;;) { premsg(' ', NUL); nchar = vgetc(); State = NORMAL; script_winsize_pp(); if (nchar == DEL) Prenum /= 10; else if (isdigit(nchar)) Prenum = Prenum * 10 + (nchar - '0'); else if (nchar == CR) { set_winsize((int)Columns, (int)Prenum, TRUE); break; } else { CLEAROPBEEP; break; } } operator = NOP; break; } if (Prenum) /* line number given */ { if (Prenum > line_count) Curpos.lnum = line_count; else Curpos.lnum = Prenum; } State = NORMAL; script_winsize_pp(); switch (nchar) { case NL: /* put Curpos at top of screen */ case CR: Topline = Prenum; updateScreen(VALID); break; case '.': /* put Curspos in middle of screen */ n = Rows / 2; goto dozcmd; case '-': /* put Curpos at bottom of screen */ n = Rows - 1; /* FALLTHROUGH */ dozcmd: { register linenr_t lp = Prenum; register long l = 0; while ((l < n) && (lp != 0)) { l += plines(lp); Topline = lp; --lp; } } updateScreen(VALID); break; default: CLEAROPBEEP; } break; /* * 2: Control commands */ case ':': if (Quote.lnum) goto dooperator; CHECKCLEAROP; docmdline(NULL); break; case K_HELP: CHECKCLEAROP; help(); break; case CTRL('L'): CHECKCLEAROP; updateScreen(CLEAR); break; case CTRL('G'): CHECKCLEAROP; fileinfo(); break; case K_CCIRCM: /* shorthand command */ CHECKCLEAROPQ; if (getaltfile((int)Prenum, (linenr_t)0, TRUE)) emsg(e_noalt); break; case 'Z': /* write, if changed, and exit */ CHECKCLEAROPQ; if (nchar != 'Z') { CLEAROPBEEP; break; } stuffReadbuff(":x\n"); break; case CTRL(']'): /* :ta to current identifier */ CHECKCLEAROPQ; case '*': /* / to current identifier */ case '#': /* ? to current identifier */ case 'K': /* run program for current identifier */ { register int col; ptr = nr2ptr(Curpos.lnum); col = Curpos.col; /* * skip to start of identifier. */ while (ptr[col] != NUL && !isidchar(ptr[col])) ++col; /* * Back up to start of identifier. This doesn't match the * real vi but I like it a little better and it shouldn't bother * anyone. */ while (col > 0 && isidchar(ptr[col - 1])) --col; if (!isidchar(ptr[col])) { CLEAROPBEEP; break; } if (Prenum) stuffnumReadbuff(Prenum); switch (c) { case '*': stuffReadbuff("/"); break; case '#': stuffReadbuff("?"); break; case 'K': stuffReadbuff(":! "); stuffReadbuff(p_kp); stuffReadbuff(" "); break; default: stuffReadbuff(":ta "); } /* * Now grab the chars in the identifier */ while (isidchar(ptr[col])) { stuffReadbuff(mkstr(ptr[col])); ++col; } stuffReadbuff("\n"); } break; case CTRL('T'): /* backwards in tag stack */ CHECKCLEAROPQ; dotag("", 2, (int)Prenum1); break; /* * Cursor motions */ case 'G': mtype = MLINE; setpcmark(); if (Prenum == 0 || Prenum > line_count) Curpos.lnum = line_count; else Curpos.lnum = Prenum; beginline(TRUE); break; case 'H': case 'M': if (c == 'M') n = Rows / 2; else n = Prenum; mtype = MLINE; Curpos.lnum = Topline; while (n && onedown((long)1)) --n; beginline(TRUE); break; case 'L': mtype = MLINE; Curpos.lnum = Botline - 1; for (n = Prenum; n && oneup((long)1); n--) ; beginline(TRUE); break; case 'l': case K_RARROW: case ' ': mtype = MCHAR; mincl = FALSE; n = Prenum1; while (n--) { if (!oneright()) { if (operator == NOP) beep(); else { if (lineempty(Curpos.lnum)) CLEAROPBEEP; else { mincl = TRUE; if (n) beep(); } } break; } } set_want_col = TRUE; break; case 'h': case K_LARROW: case CTRL('H'): case DEL: mtype = MCHAR; mincl = FALSE; n = Prenum1; while (n--) { if (!oneleft()) { if (operator != DELETE && operator != CHANGE) beep(); else if (Prenum1 == 1) CLEAROPBEEP; break; } } set_want_col = TRUE; break; case '-': flag = TRUE; /* FALLTHROUGH */ case 'k': case K_UARROW: case CTRL('P'): mtype = MLINE; if (!oneup(Prenum1)) CLEAROPBEEP; else if (flag) beginline(TRUE); break; case '+': case CR: flag = TRUE; /* FALLTHROUGH */ case 'j': case K_DARROW: case CTRL('N'): case NL: mtype = MLINE; if (!onedown(Prenum1)) CLEAROPBEEP; else if (flag) beginline(TRUE); break; /* * This is a strange motion command that helps make operators more * logical. It is actually implemented, but not documented in the * real 'vi'. This motion command actually refers to "the current * line". Commands like "dd" and "yy" are really an alternate form of * "d_" and "y_". It does accept a count, so "d3_" works to delete 3 * lines. */ case '_': lineop: mtype = MLINE; if (!onedown((long)(Prenum1 - 1))) CLEAROPBEEP; else if (operator != YANK) /* 'Y' does not move cursor */ beginline(TRUE); break; case '|': mtype = MCHAR; mincl = TRUE; beginline(FALSE); if (Prenum > 0) coladvance((colnr_t)(Prenum - 1)); Curswant = Prenum - 1; break; /* * Word Motions */ case 'B': type = 1; /* FALLTHROUGH */ case 'b': case K_SLARROW: mtype = MCHAR; mincl = FALSE; set_want_col = TRUE; if (bck_word(Prenum1, type)) CLEAROPBEEP; break; case 'E': type = 1; /* FALLTHROUGH */ case 'e': mincl = TRUE; goto dowrdcmd; case 'W': type = 1; /* FALLTHROUGH */ case 'w': case K_SRARROW: mincl = FALSE; flag = TRUE; /* * This is a little strange. To match what the real vi does, we * effectively map 'cw' to 'ce', and 'cW' to 'cE', provided that we are * not on a space or a TAB. This seems * impolite at first, but it's really more what we mean when we say * 'cw'. */ if (operator == CHANGE && (n = gcharCurpos()) != ' ' && n != TAB && n != NUL) { mincl = TRUE; flag = FALSE; } dowrdcmd: mtype = MCHAR; set_want_col = TRUE; if (flag) n = fwd_word(Prenum1, type); else n = end_word(Prenum1, type, operator == CHANGE); if (n) { CLEAROPBEEP; break; } /* * if we do a 'dw' for the last word in a line, we only delete the rest * of the line, not joining the two lines. */ if (operator == DELETE && Prenum1 == 1 && startop.lnum != Curpos.lnum) { Curpos = startop; while (oneright()) ; mincl = TRUE; } break; case '$': mtype = MCHAR; mincl = TRUE; Curswant = 29999; /* so we stay at the end */ if (!onedown((long)(Prenum1 - 1))) { CLEAROPBEEP; break; } if (Quote_block) updateScreen(NOT_VALID); break; case '^': flag = TRUE; /* FALLTHROUGH */ case '0': mtype = MCHAR; mincl = TRUE; beginline(flag); break; /* * 4: Searches */ case '?': case '/': if (!getcmdline(c, (u_char *)searchbuff)) { CLEAROP; break; } mtype = MCHAR; mincl = FALSE; set_want_col = TRUE; n = dosearch(c == '/' ? FORWARD : BACKWARD, searchbuff, FALSE, Prenum1); if (n == 0) CLEAROPBEEP; else if (n == 2) mtype = MLINE; break; case 'N': flag = 1; case 'n': mtype = MCHAR; mincl = FALSE; set_want_col = TRUE; if (!dosearch(0, NULL, flag, Prenum1)) CLEAROPBEEP; break; /* * Character searches */ case 'T': dir = BACKWARD; /* FALLTHROUGH */ case 't': type = 1; goto docsearch; case 'F': dir = BACKWARD; /* FALLTHROUGH */ case 'f': docsearch: mtype = MCHAR; mincl = TRUE; set_want_col = TRUE; if (!searchc(nchar, dir, type, Prenum1)) { CLEAROPBEEP; } break; case ',': flag = 1; /* FALLTHROUGH */ case ';': dir = flag; goto docsearch; /* nchar == NUL, thus repeat previous search */ /* * section or C function searches */ case '[': dir = BACKWARD; /* FALLTHROUGH */ case ']': mtype = MLINE; set_want_col = TRUE; flag = '{'; if (nchar != c) { if (nchar == '[' || nchar == ']') flag = '}'; else { CLEAROPBEEP; break; } } if (dir == FORWARD && operator != NOP) /* e.g. y]] searches for '}' */ flag = '}'; if (!findpar(dir, Prenum1, flag)) { CLEAROPBEEP; } break; case '%': mincl = TRUE; if (Prenum) /* {cnt}% : goto {cnt} percentage in file */ { if (Prenum > 100) CLEAROPBEEP; else { mtype = MLINE; setpcmark(); Curpos.lnum = line_count * Prenum / 100; Curpos.col = 0; } } else /* % : go to matching paren */ { mtype = MCHAR; if ((pos = showmatch()) == NULL) CLEAROPBEEP; else { setpcmark(); Curpos = *pos; set_want_col = TRUE; } } break; case '(': dir = BACKWARD; /* FALLTHROUGH */ case ')': mtype = MCHAR; if (c == ')') mincl = FALSE; else mincl = TRUE; set_want_col = TRUE; if (!findsent(dir, Prenum1)) CLEAROPBEEP; break; case '{': dir = BACKWARD; /* FALLTHROUGH */ case '}': mtype = MCHAR; mincl = FALSE; set_want_col = TRUE; if (!findpar(dir, Prenum1, NUL)) CLEAROPBEEP; break; /* * 5: Edits */ case '.': CHECKCLEAROPQ; if (!start_redo(Prenum)) CLEAROPBEEP; break; case 'u': if (Quote.lnum) goto dooperator; case K_UNDO: CHECKCLEAROPQ; u_undo((int)Prenum1); set_want_col = TRUE; break; case CTRL('R'): CHECKCLEAROPQ; u_redo((int)Prenum1); set_want_col = TRUE; break; case 'U': if (Quote.lnum) goto dooperator; CHECKCLEAROPQ; u_undoline(); set_want_col = TRUE; break; case 'r': if (Quote.lnum) { c = 'c'; goto dooperator; } CHECKCLEAROPQ; n = strlen(nr2ptr(Curpos.lnum)) - Curpos.col; if (n < Prenum1) /* not enough characters to replace */ { CLEAROPBEEP; break; } prep_redo(Prenum1, 'r', NUL, nchar); stuffnumReadbuff(Prenum1); stuffReadbuff("R"); stuffReadbuff(mkstr(nchar)); stuffReadbuff("\033"); break; case 'J': if (Quote.lnum) /* join the quoted lines */ { if (Curpos.lnum > Quote.lnum) { Prenum = Curpos.lnum - Quote.lnum + 1; Curpos.lnum = Quote.lnum; } else Prenum = Quote.lnum - Curpos.lnum + 1; Quote.lnum = 0; } CHECKCLEAROP; if (Prenum <= 1) Prenum = 2; /* default for join is two lines! */ if (Curpos.lnum + Prenum - 1 > line_count) /* beyond last line */ { CLEAROPBEEP; break; } prep_redo(Prenum, 'J', NUL, NUL); dodojoin(Prenum, TRUE, TRUE); break; case 'P': dir = BACKWARD; /* FALLTHROUGH */ case 'p': CHECKCLEAROPQ; prep_redo(Prenum, c, NUL, NUL); doput(dir, Prenum1); break; case CTRL('A'): /* add to number */ case CTRL('S'): /* subtract from number */ CHECKCLEAROPQ; { register int col; char buf[30]; int hex; /* 'x' or 'X': hexadecimal; '0': octal */ static int hexupper = FALSE; /* 0xABC */ ptr = nr2ptr(Curpos.lnum); col = Curpos.col; /* first check if we are on a hexadecimal number */ while (col > 0 && isxdigit(ptr[col])) --col; if (col > 0 && toupper(ptr[col]) == 'X' && ptr[col - 1] == '0' && isxdigit(ptr[col + 1])) --col; /* found hexadecimal number */ else { /* first search forward and then backward for start of number */ col = Curpos.col; while (ptr[col] != NUL && !isdigit(ptr[col])) ++col; while (col > 0 && isdigit(ptr[col - 1])) --col; } if (isdigit(ptr[col]) && u_saveCurpos()) { set_want_col = TRUE; prep_redo(Prenum1, c, NUL, NUL); if (ptr[col] != '0') hex = 0; /* decimal */ else { hex = toupper(ptr[col + 1]); /* assume hexadecimal */ if (hex != 'X' || !isxdigit(ptr[col + 2])) { if (isdigit(hex)) hex = '0'; /* octal */ else hex = 0; /* 0 by itself is decimal */ } } if (!hex && col > 0 && ptr[col - 1] == '-') --col; ptr += col; if (hex == '0') sscanf(ptr, "%lo", &n); else if (hex) sscanf(ptr, "%lx", &n); /* "%X" doesn't work! */ else n = atol(ptr); if (c == CTRL('A')) n += Prenum1; else n -= Prenum1; if (hex == 'X') /* skip the '0x' */ col += 2; Curpos.col = col; do /* delete the old number */ { if (isalpha(c)) { if (isupper(c)) hexupper = TRUE; else hexupper = FALSE; } delchar(FALSE); c = gcharCurpos(); } while (hex ? (hex == '0' ? c >= '0' && c <= '7' : isxdigit(c)) : isdigit(c)); if (hex == '0') sprintf(buf, "0%lo", n); else if (hexupper) sprintf(buf, "%lX", n); else if (hex) sprintf(buf, "%lx", n); else sprintf(buf, "%ld", n); insstr(buf); /* insert the new number */ --Curpos.col; updateline(); } else beep(); } break; /* * 6: Inserts */ case 'A': set_want_col = TRUE; while (oneright()) ; /* FALLTHROUGH */ case 'a': CHECKCLEAROPQ; /* Works just like an 'i'nsert on the next character. */ if (u_saveCurpos()) { if (!lineempty(Curpos.lnum)) incCurpos(); startinsert(c, FALSE, Prenum1); command_busy = TRUE; } break; case 'I': beginline(TRUE); /* FALLTHROUGH */ case 'i': CHECKCLEAROPQ; if (u_saveCurpos()) { startinsert(c, FALSE, Prenum1); command_busy = TRUE; } break; case 'o': if (Quote.lnum) /* switch start and end of quote */ { Prenum = Quote.lnum; Quote.lnum = Curpos.lnum; Curpos.lnum = Prenum; n = Quote.col; Quote.col = Curpos.col; Curpos.col = n; break; } CHECKCLEAROP; if (u_save(Curpos.lnum, (linenr_t)(Curpos.lnum + 1)) && Opencmd(FORWARD, TRUE)) { startinsert('o', TRUE, Prenum1); command_busy = TRUE; } break; case 'O': CHECKCLEAROPQ; if (u_save((linenr_t)(Curpos.lnum - 1), Curpos.lnum) && Opencmd(BACKWARD, TRUE)) { startinsert('O', TRUE, Prenum1); command_busy = TRUE; } break; case 'R': if (Quote.lnum) { c = 'c'; Quote.col = QUOTELINE; goto dooperator; } CHECKCLEAROPQ; if (u_saveCurpos()) { startinsert('R', FALSE, Prenum1); command_busy = TRUE; } break; /* * 7: Operators */ case '~': /* swap case */ /* * if tilde is not an operator and Quoting is off: swap case * of a single character */ if (!p_to && !Quote.lnum) { CHECKCLEAROPQ; if (lineempty(Curpos.lnum)) { CLEAROPBEEP; break; } prep_redo(Prenum, '~', NUL, NUL); if (!u_saveCurpos()) break; for (; Prenum1 > 0; --Prenum1) { if (gcharCurpos() == NUL) break; swapchar(&Curpos); incCurpos(); } set_want_col = TRUE; CHANGED; updateline(); break; } /*FALLTHROUGH*/ case 'd': case 'c': case 'y': case '>': case '<': case '!': case '=': case 'V': dooperator: n = strchr(opchars, c) - opchars + 1; if (n == operator) /* double operator works on lines */ goto lineop; CHECKCLEAROP; if (Prenum != 0) opnum = Prenum; startop = Curpos; operator = n; break; /* * 8: Abbreviations */ /* when quoting the next commands are operators */ case 'S': case 'Y': case 'D': case 'C': case 'x': case 'X': case 's': if (Quote.lnum) { static char trans[] = "ScYyDdCcxdXdsc"; if (isupper(c)) /* uppercase means linewise */ Quote.col = QUOTELINE; c = *(strchr(trans, c) + 1); goto dooperator; } case '&': CHECKCLEAROPQ; if (Prenum) stuffnumReadbuff(Prenum); if (c == 'S') { beginline((int)p_ai); substituting = TRUE; } else if (c == 'Y' && p_ye) c = 'Z'; { static char *(ar[9]) = {"dl", "dh", "d$", "c$", "cl", "c$", "yy", "y$", ":s\r"}; static char *str = "xXDCsSYZ&"; stuffReadbuff(ar[strchr(str, c) - str]); } break; /* * 9: Marks */ case 'm': CHECKCLEAROP; if (!setmark(nchar)) CLEAROPBEEP; break; case '\'': flag = TRUE; /* FALLTHROUGH */ case '`': pos = getmark(nchar, (operator == NOP)); if (pos == (FPOS *)-1) /* jumped to other file */ { if (flag) beginline(TRUE); break; } if (pos != NULL) setpcmark(); cursormark: if (pos == NULL) CLEAROPBEEP; else { Curpos = *pos; if (flag) beginline(TRUE); } mtype = flag ? MLINE : MCHAR; mincl = FALSE; /* ignored if not MCHAR */ set_want_col = TRUE; break; case CTRL('O'): /* goto older pcmark */ Prenum1 = -Prenum1; /* FALLTHROUGH */ case CTRL('I'): /* goto newer pcmark */ CHECKCLEAROPQ; pos = movemark((int)Prenum1); if (pos == (FPOS *)-1) /* jump to other file */ { set_want_col = TRUE; break; } goto cursormark; /* * 10. Buffer setting */ case '"': CHECKCLEAROP; if (isalnum(nchar) || nchar == '.') { yankbuffer = nchar; opnum = Prenum; /* remember count before '"' */ } else CLEAROPBEEP; break; /* * 11. Quoting */ case 'q': case 'Q': case CTRL('Q'): CHECKCLEAROP; Quote_block = FALSE; if (Quote.lnum) /* stop quoting */ { Quote.lnum = 0; updateScreen(NOT_VALID); /* delete the inversion */ } else /* start quoting */ { Quote = Curpos; if (c == 'Q') /* linewise */ Quote.col = QUOTELINE; else if (c == CTRL('Q')) /* blockwise */ Quote_block = TRUE; updateline(); /* start the inversion */ } break; /* * 12. Suspend */ case CTRL('Z'): CLEAROP; Quote.lnum = 0; /* stop quoting */ stuffReadbuff(":st!\r"); /* no autowrite */ break; /* * The end */ case ESC: if (Quote.lnum) { Quote.lnum = 0; /* stop quoting */ updateScreen(NOT_VALID); } default: /* not a known command */ CLEAROPBEEP; break; } /* end of switch on command character */ /* * if we didn't start or finish an operator, reset yankbuffer, unless we * need it later. */ if (!finish_op && !operator && strchr("\"DCYSsXx", c) == NULL) yankbuffer = 0; /* * If an operation is pending, handle it... */ if ((Quote.lnum || finish_op) && operator != NOP) { if (operator != YANK && !Quote.lnum) /* can't redo yank */ { prep_redo(Prenum, opchars[operator - 1], c, nchar); if (c == '/' || c == '?') /* was a search */ { AppendToRedobuff(searchbuff); AppendToRedobuff(NL_STR); } } if (redo_Quote_busy) { startop = Curpos; Curpos.lnum += redo_Quote_nlines - 1; switch (redo_Quote_type) { case 'Q': Quote.col = QUOTELINE; break; case CTRL('Q'): Quote_block = TRUE; break; case 'q': if (redo_Quote_nlines <= 1) Curpos.col += redo_Quote_col; else Curpos.col = redo_Quote_col; break; } if (redo_Quote_col == 29999) { Curswant = 29999; coladvance(29999); } } else if (Quote.lnum) startop = Quote; if (lt(startop, Curpos)) { endop = Curpos; Curpos = startop; } else { endop = startop; startop = Curpos; } nlines = endop.lnum - startop.lnum + 1; if (Quote.lnum || redo_Quote_busy) { if (Quote_block) /* block mode */ { startvcol = getvcol(&startop, 2); n = getvcol(&endop, 2); if (n < startvcol) startvcol = n; /* if '$' was used, get endvcol from longest line */ if (Curswant == 29999) { Curpos.col = 29999; endvcol = 0; for (Curpos.lnum = startop.lnum; Curpos.lnum <= endop.lnum; ++Curpos.lnum) if ((n = getvcol(&Curpos, 3)) > endvcol) endvcol = n; Curpos = startop; } else if (redo_Quote_busy) endvcol = startvcol + redo_Quote_col; else { endvcol = getvcol(&startop, 3); n = getvcol(&endop, 3); if (n > endvcol) endvcol = n; } coladvance(startvcol); } /* * prepare to redo quoting: this is based on the size * of the quoted text */ if (operator != YANK) /* can't redo yank */ { prep_redo(0L, 'q', opchars[operator - 1], NUL); if (Quote_block) redo_Quote_type = CTRL('Q'); else if (Quote.col == QUOTELINE) redo_Quote_type = 'Q'; else redo_Quote_type = 'q'; if (Curswant == 29999) redo_Quote_col = 29999; else if (Quote_block) redo_Quote_col = endvcol - startvcol; else if (nlines > 1) redo_Quote_col = endop.col; else redo_Quote_col = endop.col - startop.col; redo_Quote_nlines = nlines; } mincl = TRUE; if (Quote.col == QUOTELINE) mtype = MLINE; else mtype = MCHAR; redo_Quote_busy = FALSE; /* * Switch quoting off now, so screen updating does * not show inverted text when the screen is redrawn. * With YANK and sometimes with COLON there is no screen redraw, so * it is done here to remove the inverted part. */ Quote.lnum = 0; if (operator == YANK || operator == COLON) updateScreen(NOT_VALID); } set_want_col = 1; if (!mincl && !equal(startop, endop)) oneless = 1; else oneless = 0; switch (operator) { case LSHIFT: case RSHIFT: adjust_lnum(); doshift(operator); break; case DELETE: dodelete(); break; case YANK: doyank(FALSE); break; case CHANGE: dochange(); break; case FILTER: AppendToRedobuff("!\n"); /* strange but necessary */ case INDENT: case COLON: adjust_lnum(); sprintf(IObuff, ":%ld,%ld", (long)startop.lnum, (long)endop.lnum); stuffReadbuff(IObuff); if (operator != COLON) stuffReadbuff("!"); if (operator == INDENT) { stuffReadbuff(p_ep); stuffReadbuff("\n"); } /* docmdline() does the rest */ break; case TILDE: case UPPER: case LOWER: dotilde(); break; case FORMAT: adjust_lnum(); doformat(); break; default: CLEAROPBEEP; } operator = NOP; Quote_block = FALSE; yankbuffer = 0; } normal_end: premsg(-1, NUL); if (restart_edit && operator == NOP && Quote.lnum == 0 && !command_busy && stuff_empty() && yankbuffer == 0) startinsert(NUL, FALSE, 1L); }
static void mainloop(void) { int step = srows / PAGESTEPS; int hstep = scols / PAGESTEPS; int c; term_setup(); signal(SIGCONT, sigcont); loadpage(num); srow = prow; scol = -scols / 2; draw(); while ((c = readkey()) != -1) { if (c == 'q') break; if (c == 'e' && reload()) break; switch (c) { /* commands that do not require redrawing */ case 'o': numdiff = num - getcount(num); break; case 'Z': zoom_def = getcount(zoom); break; case 'i': printinfo(); break; case 27: count = 0; break; case 'm': setmark(readkey()); break; case 'd': sleep(getcount(1)); break; default: if (isdigit(c)) count = count * 10 + c - '0'; } switch (c) { /* commands that require redrawing */ case CTRLKEY('f'): case 'J': if (!loadpage(num + getcount(1))) srow = prow; break; case CTRLKEY('b'): case 'K': if (!loadpage(num - getcount(1))) srow = prow; break; case 'G': setmark('\''); if (!loadpage(getcount(doc_pages(doc) - numdiff) + numdiff)) srow = prow; break; case 'O': numdiff = num - getcount(num); setmark('\''); if (!loadpage(num + numdiff)) srow = prow; break; case 'z': zoom_page(getcount(zoom_def)); break; case 'w': zoom_page(pcols ? zoom * scols / pcols : zoom); break; case 'W': if (lmargin() < rmargin()) zoom_page(zoom * (scols - hstep) / (rmargin() - lmargin())); break; case 'f': zoom_page(prows ? zoom * srows / prows : zoom); break; case 'r': rotate = getcount(0); if (!loadpage(num)) srow = prow; break; case '`': case '\'': jmpmark(readkey(), c == '`'); break; case 'j': srow += step * getcount(1); break; case 'k': srow -= step * getcount(1); break; case 'l': scol += hstep * getcount(1); break; case 'h': scol -= hstep * getcount(1); break; case 'H': srow = prow; break; case 'L': srow = prow + prows - srows; break; case 'M': srow = prow + prows / 2 - srows / 2; break; case 'C': scol = -scols / 2; break; case ' ': case CTRLKEY('d'): srow += srows * getcount(1) - step; break; case 127: case CTRLKEY('u'): srow -= srows * getcount(1) - step; break; case '[': scol = pcol; break; case ']': scol = pcol + pcols - scols; break; case '{': scol = pcol + lmargin() - hstep / 2; break; case '}': scol = pcol + rmargin() + hstep / 2 - scols; break; case CTRLKEY('l'): break; case 'I': invert = !invert; loadpage(num); break; default: /* no need to redraw */ continue; } srow = MAX(prow - srows + MARGIN, MIN(prow + prows - MARGIN, srow)); scol = MAX(pcol - scols + MARGIN, MIN(pcol + pcols - MARGIN, scol)); draw(); } term_cleanup(); }
static void copyinverted(void) { char *cp; int c; int type; /* reference type (mark character) */ char symbol[PATLEN + 1]; /* note: this code was expanded in-line for speed */ /* while (scanpast('\n') != NULL) { */ /* other macros were replaced by code using cp instead of blockp */ cp = blockp; for (;;) { setmark('\n'); do { /* innermost loop optimized to only one test */ while (*cp != '\n') { dbputc(*cp++); } } while (*++cp == '\0' && (cp = readblock()) != NULL); dbputc('\n'); /* copy the newline */ /* get the next character */ if (*(cp + 1) == '\0') { cp = readblock(); } /* exit if at the end of this file's data */ if (cp == NULL) { break; } switch (*cp) { case '\n': lineoffset = dboffset + 1; continue; case '\t': dbputc('\t'); blockp = cp; type = getrefchar(); switch (type) { case NEWFILE: /* file name */ return; case INCLUDE: /* #included file */ putinclude(symbol); goto output; } dbputc(type); skiprefchar(); getstring(symbol); goto output; } c = *cp; if (c & 0200) { /* digraph char? */ c = dichar1[(c & 0177) / 8]; } /* if this is a symbol */ if (isalpha(c) || c == '_') { blockp = cp; getstring(symbol); type = ' '; output: putposting(symbol, type); putstring(symbol); if (blockp == NULL) { return; } cp = blockp; } } blockp = cp; }
/* * Main command processor. * Accept and execute commands until a quit command. */ void commands(void) { int c = 0; int action; char *cbuf; int newaction; int save_search_type; char *extra; char tbuf[2]; PARG parg; IFILE old_ifile; IFILE new_ifile; char *tagfile; search_type = SRCH_FORW; wscroll = (sc_height + 1) / 2; newaction = A_NOACTION; for (;;) { mca = 0; cmd_accept(); number = 0; curropt = NULL; /* * See if any signals need processing. */ if (sigs) { psignals(); if (quitting) quit(QUIT_SAVED_STATUS); } /* * Display prompt and accept a character. */ cmd_reset(); prompt(); if (sigs) continue; if (newaction == A_NOACTION) c = getcc(); again: if (sigs) continue; if (newaction != A_NOACTION) { action = newaction; newaction = A_NOACTION; } else { /* * If we are in a multicharacter command, call mca_char. * Otherwise we call fcmd_decode to determine the * action to be performed. */ if (mca) switch (mca_char(c)) { case MCA_MORE: /* * Need another character. */ c = getcc(); goto again; case MCA_DONE: /* * Command has been handled by mca_char. * Start clean with a prompt. */ continue; case NO_MCA: /* * Not a multi-char command * (at least, not anymore). */ break; } /* * Decode the command character and decide what to do. */ if (mca) { /* * We're in a multichar command. * Add the character to the command buffer * and display it on the screen. * If the user backspaces past the start * of the line, abort the command. */ if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0) continue; cbuf = get_cmdbuf(); } else { /* * Don't use cmd_char if we're starting fresh * at the beginning of a command, because we * don't want to echo the command until we know * it is a multichar command. We also don't * want erase_char/kill_char to be treated * as line editing characters. */ tbuf[0] = (char)c; tbuf[1] = '\0'; cbuf = tbuf; } extra = NULL; action = fcmd_decode(cbuf, &extra); /* * If an "extra" string was returned, * process it as a string of command characters. */ if (extra != NULL) ungetsc(extra); } /* * Clear the cmdbuf string. * (But not if we're in the prefix of a command, * because the partial command string is kept there.) */ if (action != A_PREFIX) cmd_reset(); switch (action) { case A_DIGIT: /* * First digit of a number. */ start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE); goto again; case A_F_WINDOW: /* * Forward one window (and set the window size). */ if (number > 0) swindow = (int)number; /* FALLTHRU */ case A_F_SCREEN: /* * Forward one screen. */ if (number <= 0) number = get_swindow(); cmd_exec(); if (show_attn) set_attnpos(bottompos); forward((int)number, 0, 1); break; case A_B_WINDOW: /* * Backward one window (and set the window size). */ if (number > 0) swindow = (int)number; /* FALLTHRU */ case A_B_SCREEN: /* * Backward one screen. */ if (number <= 0) number = get_swindow(); cmd_exec(); backward((int)number, 0, 1); break; case A_F_LINE: /* * Forward N (default 1) line. */ if (number <= 0) number = 1; cmd_exec(); if (show_attn == OPT_ONPLUS && number > 1) set_attnpos(bottompos); forward((int)number, 0, 0); break; case A_B_LINE: /* * Backward N (default 1) line. */ if (number <= 0) number = 1; cmd_exec(); backward((int)number, 0, 0); break; case A_F_SKIP: /* * Skip ahead one screen, and then number lines. */ if (number <= 0) { number = get_swindow(); } else { number += get_swindow(); } cmd_exec(); if (show_attn == OPT_ONPLUS) set_attnpos(bottompos); forward((int)number, 0, 1); break; case A_FF_LINE: /* * Force forward N (default 1) line. */ if (number <= 0) number = 1; cmd_exec(); if (show_attn == OPT_ONPLUS && number > 1) set_attnpos(bottompos); forward((int)number, 1, 0); break; case A_BF_LINE: /* * Force backward N (default 1) line. */ if (number <= 0) number = 1; cmd_exec(); backward((int)number, 1, 0); break; case A_FF_SCREEN: /* * Force forward one screen. */ if (number <= 0) number = get_swindow(); cmd_exec(); if (show_attn == OPT_ONPLUS) set_attnpos(bottompos); forward((int)number, 1, 0); break; case A_F_FOREVER: /* * Forward forever, ignoring EOF. */ newaction = forw_loop(0); break; case A_F_UNTIL_HILITE: newaction = forw_loop(1); break; case A_F_SCROLL: /* * Forward N lines * (default same as last 'd' or 'u' command). */ if (number > 0) wscroll = (int)number; cmd_exec(); if (show_attn == OPT_ONPLUS) set_attnpos(bottompos); forward(wscroll, 0, 0); break; case A_B_SCROLL: /* * Forward N lines * (default same as last 'd' or 'u' command). */ if (number > 0) wscroll = (int)number; cmd_exec(); backward(wscroll, 0, 0); break; case A_FREPAINT: /* * Flush buffers, then repaint screen. * Don't flush the buffers on a pipe! */ clear_buffers(); /* FALLTHRU */ case A_REPAINT: /* * Repaint screen. */ cmd_exec(); repaint(); break; case A_GOLINE: /* * Go to line N, default beginning of file. */ if (number <= 0) number = 1; cmd_exec(); jump_back(number); break; case A_PERCENT: /* * Go to a specified percentage into the file. */ if (number < 0) { number = 0; fraction = 0; } if (number > 100) { number = 100; fraction = 0; } cmd_exec(); jump_percent((int)number, fraction); break; case A_GOEND: /* * Go to line N, default end of file. */ cmd_exec(); if (number <= 0) jump_forw(); else jump_back(number); break; case A_GOPOS: /* * Go to a specified byte position in the file. */ cmd_exec(); if (number < 0) number = 0; jump_line_loc((off_t) number, jump_sline); break; case A_STAT: /* * Print file name, etc. */ if (ch_getflags() & CH_HELPFILE) break; cmd_exec(); parg.p_string = eq_message(); error("%s", &parg); break; case A_VERSION: /* * Print version number, without the "@(#)". */ cmd_exec(); dispversion(); break; case A_QUIT: /* * Exit. */ if (curr_ifile != NULL_IFILE && ch_getflags() & CH_HELPFILE) { /* * Quit while viewing the help file * just means return to viewing the * previous file. */ hshift = save_hshift; if (edit_prev(1) == 0) break; } if (extra != NULL) quit(*extra); quit(QUIT_OK); break; /* * Define abbreviation for a commonly used sequence below. */ #define DO_SEARCH() \ if (number <= 0) number = 1; \ mca_search(); \ cmd_exec(); \ multi_search(NULL, (int)number); case A_F_SEARCH: /* * Search forward for a pattern. * Get the first char of the pattern. */ search_type = SRCH_FORW; if (number <= 0) number = 1; mca_search(); c = getcc(); goto again; case A_B_SEARCH: /* * Search backward for a pattern. * Get the first char of the pattern. */ search_type = SRCH_BACK; if (number <= 0) number = 1; mca_search(); c = getcc(); goto again; case A_FILTER: search_type = SRCH_FORW | SRCH_FILTER; mca_search(); c = getcc(); goto again; case A_AGAIN_SEARCH: /* * Repeat previous search. */ DO_SEARCH(); break; case A_T_AGAIN_SEARCH: /* * Repeat previous search, multiple files. */ search_type |= SRCH_PAST_EOF; DO_SEARCH(); break; case A_REVERSE_SEARCH: /* * Repeat previous search, in reverse direction. */ save_search_type = search_type; search_type = SRCH_REVERSE(search_type); DO_SEARCH(); search_type = save_search_type; break; case A_T_REVERSE_SEARCH: /* * Repeat previous search, * multiple files in reverse direction. */ save_search_type = search_type; search_type = SRCH_REVERSE(search_type); search_type |= SRCH_PAST_EOF; DO_SEARCH(); search_type = save_search_type; break; case A_UNDO_SEARCH: undo_search(); break; case A_HELP: /* * Help. */ if (ch_getflags() & CH_HELPFILE) break; if (ungot != NULL || unget_end) { error(less_is_more ? "Invalid option -p h" : "Invalid option ++h", NULL_PARG); break; } cmd_exec(); save_hshift = hshift; hshift = 0; (void) edit(FAKE_HELPFILE); break; case A_EXAMINE: /* * Edit a new file. Get the filename. */ if (secure) { error("Command not available", NULL_PARG); break; } start_mca(A_EXAMINE, "Examine: ", ml_examine, 0); c = getcc(); goto again; case A_VISUAL: /* * Invoke an editor on the input file. */ if (secure) { error("Command not available", NULL_PARG); break; } if (ch_getflags() & CH_HELPFILE) break; if (strcmp(get_filename(curr_ifile), "-") == 0) { error("Cannot edit standard input", NULL_PARG); break; } if (curr_altfilename != NULL) { error("WARNING: This file was viewed via " "LESSOPEN", NULL_PARG); } start_mca(A_SHELL, "!", ml_shell, 0); /* * Expand the editor prototype string * and pass it to the system to execute. * (Make sure the screen is displayed so the * expansion of "+%lm" works.) */ make_display(); cmd_exec(); lsystem(pr_expand(editproto, 0), NULL); break; case A_NEXT_FILE: /* * Examine next file. */ if (ntags()) { error("No next file", NULL_PARG); break; } if (number <= 0) number = 1; if (edit_next((int)number)) { if (get_quit_at_eof() && eof_displayed() && !(ch_getflags() & CH_HELPFILE)) quit(QUIT_OK); parg.p_string = (number > 1) ? "(N-th) " : ""; error("No %snext file", &parg); } break; case A_PREV_FILE: /* * Examine previous file. */ if (ntags()) { error("No previous file", NULL_PARG); break; } if (number <= 0) number = 1; if (edit_prev((int)number)) { parg.p_string = (number > 1) ? "(N-th) " : ""; error("No %sprevious file", &parg); } break; case A_NEXT_TAG: if (number <= 0) number = 1; tagfile = nexttag((int)number); if (tagfile == NULL) { error("No next tag", NULL_PARG); break; } if (edit(tagfile) == 0) { off_t pos = tagsearch(); if (pos != -1) jump_loc(pos, jump_sline); } break; case A_PREV_TAG: if (number <= 0) number = 1; tagfile = prevtag((int)number); if (tagfile == NULL) { error("No previous tag", NULL_PARG); break; } if (edit(tagfile) == 0) { off_t pos = tagsearch(); if (pos != -1) jump_loc(pos, jump_sline); } break; case A_INDEX_FILE: /* * Examine a particular file. */ if (number <= 0) number = 1; if (edit_index((int)number)) error("No such file", NULL_PARG); break; case A_REMOVE_FILE: if (ch_getflags() & CH_HELPFILE) break; old_ifile = curr_ifile; new_ifile = getoff_ifile(curr_ifile); if (new_ifile == NULL_IFILE) { ring_bell(); break; } if (edit_ifile(new_ifile) != 0) { reedit_ifile(old_ifile); break; } del_ifile(old_ifile); break; case A_OPT_TOGGLE: optflag = OPT_TOGGLE; optgetname = FALSE; mca_opt_toggle(); c = getcc(); goto again; case A_DISP_OPTION: /* * Report a flag setting. */ optflag = OPT_NO_TOGGLE; optgetname = FALSE; mca_opt_toggle(); c = getcc(); goto again; case A_FIRSTCMD: /* * Set an initial command for new files. */ start_mca(A_FIRSTCMD, "+", NULL, 0); c = getcc(); goto again; case A_SHELL: /* * Shell escape. */ if (secure) { error("Command not available", NULL_PARG); break; } start_mca(A_SHELL, "!", ml_shell, 0); c = getcc(); goto again; case A_SETMARK: /* * Set a mark. */ if (ch_getflags() & CH_HELPFILE) break; start_mca(A_SETMARK, "mark: ", (void*)NULL, 0); c = getcc(); if (c == erase_char || c == erase2_char || c == kill_char || c == '\n' || c == '\r') break; setmark(c); break; case A_GOMARK: /* * Go to a mark. */ start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0); c = getcc(); if (c == erase_char || c == erase2_char || c == kill_char || c == '\n' || c == '\r') break; cmd_exec(); gomark(c); break; case A_PIPE: if (secure) { error("Command not available", NULL_PARG); break; } start_mca(A_PIPE, "|mark: ", (void*)NULL, 0); c = getcc(); if (c == erase_char || c == erase2_char || c == kill_char) break; if (c == '\n' || c == '\r') c = '.'; if (badmark(c)) break; pipec = c; start_mca(A_PIPE, "!", ml_shell, 0); c = getcc(); goto again; case A_B_BRACKET: case A_F_BRACKET: start_mca(action, "Brackets: ", (void*)NULL, 0); c = getcc(); goto again; case A_LSHIFT: if (number > 0) shift_count = number; else number = (shift_count > 0) ? shift_count : sc_width / 2; if (number > hshift) number = hshift; hshift -= number; screen_trashed = 1; break; case A_RSHIFT: if (number > 0) shift_count = number; else number = (shift_count > 0) ? shift_count : sc_width / 2; hshift += number; screen_trashed = 1; break; case A_PREFIX: /* * The command is incomplete (more chars are needed). * Display the current char, so the user knows * what's going on, and get another character. */ if (mca != A_PREFIX) { cmd_reset(); start_mca(A_PREFIX, " ", (void*)NULL, CF_QUIT_ON_ERASE); (void) cmd_char(c); } c = getcc(); goto again; case A_NOACTION: break; default: ring_bell(); break; } } }
/* * mouse_in_pico * * When the mouse goes down in the body we set the mark and start * tracking. * * As the mouse moves we update the dot and redraw the screen. * * If the mouse moves above or below the pico body region of the * screen we scroll the text and update the dot position. * * When the mouse comes up we clean up. If the mouse did not * move, then we clear the mark and turn off the selection. * * Most of the mouse processing is handled here. The exception is * mouse down in the header. Can't call HeaderEditor() from here so * we send up the KEY_MOUSE character, which gets dispatched to * mousepress(), which _can_ call HeaderEditor(). */ unsigned long mouse_in_pico(unsigned long mevent, int row, int col, int button, int flags) { unsigned long rv = 0; /* Our return value. */ int trow, tcol; /* translated row and col. */ static int lheader = FALSE; /* Mouse down was in header. */ /* * What's up. */ switch (mevent) { case M_EVENT_DOWN: if(button != M_BUTTON_LEFT) break; /* Ignore mouse down if not in pico body region. */ if (row < 2 || row > term.t_nrow - (term.t_mrow+1)) { clear_mtrack (); break; } /* Detect double clicks. Not that we do anything with em, just * detect them. */ #ifdef DOS #ifdef CLOCKS_PER_SEC doubleclick = (lrow == row && lcol == col && clock() < (lastcalled + CLOCKS_PER_SEC/2)); #else #ifdef CLK_TCK doubleclick = (lrow == row && lcol == col && clock() < (lastcalled + CLK_TCK/2)); #else doubleclick = FALSE; #endif #endif lastcalled = clock(); #else doubleclick = (lrow == row && lcol == col && time(0) < (lastcalled + 2)); lastcalled = time(0); #endif lheader = FALSE; /* Rember mouse down position. */ levent = mevent; lrow = row; lcol = col; lbutton = button; lflags = flags; /* Mouse down in body? */ if (row < (Pmaster ? ComposerTopLine : 2)) { /* Mouse down in message header -> no tracking, just remember * where */ lheader = TRUE; } else { /* Mouse down in message. * If no shift key and an existing mark -> clear the mark. * If shift key and no existing mark -> set mark before moving */ if (!(flags & M_KEY_SHIFT) && curwp->w_markp) setmark (0,1); /* this clears the mark. */ else if (flags & M_KEY_SHIFT && !curwp->w_markp) setmark (0,1); /* while this sets the mark. */ /* Reposition dot to mouse down. */ move_dot_to (row, col); /* Set the mark to dot if no existing mark. */ if (curwp->w_markp == NULL) setmark (0,1); /* Track mouse movement. */ register_mtrack (mouse_in_pico); update (); lheader = FALSE; /* Just to be sure. */ } break; case M_EVENT_TRACK: /* Mouse tracking. */ if (lheader) /* Ignore mouse movement in header. */ break; /* If above or below body, scroll body and adjust the row and col. */ if (row < (Pmaster ? ComposerTopLine : 2)) { /* Scroll text down screen and move dot to top left corner. */ scrollupline (0,1); trow = (Pmaster) ? ComposerTopLine : 2; tcol = 0; } else if (row > term.t_nrow - (term.t_mrow + 1)) { /* Scroll text up screen and move dot to bottom right corner. */ scrolldownline (0,1); trow = term.t_nrow - (term.t_mrow + 1); tcol = term.t_ncol; } else { trow = row; tcol = col; } /* Move dot to target column. */ move_dot_to (trow, tcol); /* Update screen. */ update (); break; case M_EVENT_UP: if(button == M_BUTTON_RIGHT){ #ifdef _WINDOWS pico_popup(); #endif break; } else if(button != M_BUTTON_LEFT) break; if (lheader) { lheader = FALSE; /* Last down in header. */ if (row == lrow && col == lcol) { /* Mouse up and down in same place in header. Means the * user want to edit the header. Return KEY_MOUSE which * will cause mousepress to be called, which will * call HeaderEditor. Can't call HeaderEditor from here * because that would mess up layering. */ if (curwp->w_marko) setmark (0,1); rv = (unsigned long) KEY_MOUSE; } } else { /* If up at same place, clear mark */ if (curwp->w_markp == curwp->w_dotp && curwp->w_marko == curwp->w_doto) { setmark (0,1); curwp->w_flag |= WFMOVE; } clear_mtrack (); update (); } break; } return(rv); }
/* * $Log: region.c,v $ * Revision 1.3 2001/05/25 15:37:21 amura * now buffers have only one mark (before windows have one mark) * * Revision 1.2 2001/02/18 17:07:27 amura * append AUTOSAVE feature (but NOW not work) * * Revision 1.1.1.1 2000/06/27 01:47:56 amura * import to CVS * */ #include "config.h" /* 90.12.20 by S.Yoshida */ #include "def.h" #ifdef UNDO #include "undo.h" #endif int getregion pro((REGION*)); static int setsize pro((REGION*,RSIZE)); #ifdef CHGMISC /* 97.11.10 by M.Suzuki */ copywordregion(f, n) { setmark(f, n); forwword(f,n); return copyregion(f, n); }
void setlim(struct xy *p) { float t,delta,sign; struct z z; float lb,ub; int lbf,ubf; lb = p->xlb; ub = p->xub; delta = ub-lb; if(p->xqf) { if(delta*p->xquant <=0 ) badarg(); return; } sign = 1; lbf = p->xlbf; ubf = p->xubf; if(delta < 0) { sign = -1; t = lb; lb = ub; ub = t; t = lbf; lbf = ubf; ubf = t; } else if(delta == 0) { if(ub > 0) { ub = 2*ub; lb = 0; } else if(lb < 0) { lb = 2*lb; ub = 0; } else { ub = 1; lb = -1; } } if(p->xf==log10 && lb>0 && ub>lb) { z = setloglim(lbf,ubf,lb,ub); p->xlb = z.lb; p->xub = z.ub; p->xmult *= z.mult; p->xquant = z.quant; if(setmark(p, 0)<2) { p->xqf = lbf = ubf = 1; lb = z.lb; ub = z.ub; } else return; } z = setlinlim(lbf,ubf,lb,ub); if(sign > 0) { p->xlb = z.lb; p->xub = z.ub; } else { p->xlb = z.ub; p->xub = z.lb; } p->xmult *= z.mult; p->xquant = sign*z.quant; }
void VarCode::unmark() { setmark(2); setmark(0); }
void normal() { register int c; long n; int flag = FALSE; int flag2 = FALSE; int type = 0; /* type of operation */ int dir = FORWARD; /* search direction */ int nchar = NUL; int finish_op; linenr_t Prenum1; char_u searchbuff[CMDBUFFSIZE];/* buffer for search string */ FPOS *pos = NULL; /* init for gcc */ register char_u *ptr; int command_busy = FALSE; static int didwarn = FALSE; /* warned for broken inversion */ int modified = FALSE; /* changed current buffer */ int ctrl_w = FALSE; /* got CTRL-W command */ /* the visual area is remembered for reselection */ static linenr_t resel_Visual_nlines; /* number of lines */ static int resel_Visual_type = 0; /* type 'v', 'V' or CTRL-V */ static colnr_t resel_Visual_col; /* number of columns or end column */ /* the visual area is remembered for redo */ static linenr_t redo_Visual_nlines; /* number of lines */ static int redo_Visual_type = 0; /* type 'v', 'V' or CTRL-V */ static colnr_t redo_Visual_col; /* number of columns or end column */ static long redo_Visual_Prenum; /* Prenum for operator */ Prenum = 0; /* * If there is an operator pending, then the command we take this time * will terminate it. Finish_op tells us to finish the operation before * returning this time (unless the operation was cancelled). */ finish_op = (operator != NOP); if (!finish_op && !yankbuffer) opnum = 0; if (p_sc && (vpeekc() == NUL || KeyTyped == TRUE)) premsg(NUL, NUL); State = NORMAL_BUSY; c = vgetc(); getcount: /* Pick up any leading digits and compute 'Prenum' */ while ((c >= '1' && c <= '9') || (Prenum != 0 && (c == DEL || c == '0'))) { if (c == DEL) Prenum /= 10; else Prenum = Prenum * 10 + (c - '0'); if (Prenum < 0) /* got too large! */ Prenum = 999999999; premsg(ctrl_w ? Ctrl('W') : ' ', NUL); c = vgetc(); } /* * If we got CTRL-W there may be a/another count */ if (c == Ctrl('W') && !ctrl_w) { ctrl_w = TRUE; opnum = Prenum; /* remember first count */ Prenum = 0; State = ONLYKEY; /* no mapping for nchar, but keys */ premsg(c, NUL); c = vgetc(); /* get next character */ goto getcount; /* jump back */ } /* * If we're in the middle of an operator (including after entering a yank * buffer with ") AND we had a count before the * operator, then that count overrides the current value of Prenum. What * this means effectively, is that commands like "3dw" get turned into * "d3w" which makes things fall into place pretty neatly. * If you give a count before AND after the operator, they are multiplied. */ if (opnum != 0) { if (Prenum) Prenum *= opnum; else Prenum = opnum; opnum = 0; } Prenum1 = (Prenum == 0 ? 1 : Prenum); /* Prenum often defaults to 1 */ premsg(c, NUL); /* * get an additional character if we need one * for CTRL-W we already got it when looking for a count */ if (ctrl_w) { nchar = c; c = Ctrl('W'); premsg(c, nchar); } else if (strchr("@zZtTfF[]mg'`\"", c) || (c == 'q' && !Recording && !Exec_reg) || (c == 'r' && !VIsual.lnum)) { State = NOMAPPING; nchar = vgetc(); /* no macro mapping for this char */ premsg(c, nchar); } if (p_sc) flushbuf(); /* flush the premsg() characters onto the screen so we can see them while the command is being executed */ /* * For commands that don't get another character we can put the State back to * NORMAL and check for a window size change. */ if (STRCHR("z:/?", c) == NULL) State = NORMAL; if (nchar == ESC) { CLEAROP; goto normal_end; } switch (c) { /* * 0: Macros */ case 'q': /* (stop) recording into a named register */ CHECKCLEAROP; /* command is ignored while executing a register */ if (!Exec_reg && dorecord(nchar) == FAIL) CLEAROPBEEP; break; case '@': /* execute a named buffer */ CHECKCLEAROP; while (Prenum1--) { if (doexecbuf(nchar) == FAIL) { CLEAROPBEEP; break; } } break; /* * 1: Screen positioning commands */ case Ctrl('D'): flag = TRUE; case Ctrl('U'): CHECKCLEAROP; if (Prenum) curwin->w_p_scroll = (Prenum > curwin->w_height) ? curwin->w_height : Prenum; n = (curwin->w_p_scroll <= curwin->w_height) ? curwin->w_p_scroll : curwin->w_height; if (flag) { curwin->w_topline += n; if (curwin->w_topline > curbuf->b_ml.ml_line_count) curwin->w_topline = curbuf->b_ml.ml_line_count; comp_Botline(curwin); /* compute curwin->w_botline */ (void)onedown(n); } else { if (n >= curwin->w_cursor.lnum) n = curwin->w_cursor.lnum - 1; Prenum1 = curwin->w_cursor.lnum - n; scrolldown(n); if (Prenum1 < curwin->w_cursor.lnum) curwin->w_cursor.lnum = Prenum1; } beginline(TRUE); updateScreen(VALID); break; case Ctrl('B'): case K_SUARROW: dir = BACKWARD; case Ctrl('F'): case K_SDARROW: CHECKCLEAROP; (void)onepage(dir, Prenum1); break; case Ctrl('E'): CHECKCLEAROP; scrollup(Prenum1); /* We may have moved to another line -- webb */ coladvance(curwin->w_curswant); updateScreen(VALID); break; case Ctrl('Y'): CHECKCLEAROP; scrolldown(Prenum1); /* We may have moved to another line -- webb */ coladvance(curwin->w_curswant); updateScreen(VALID); break; case 'z': CHECKCLEAROP; if (isdigit(nchar)) { /* * we misuse some variables to be able to call premsg() */ operator = c; opnum = Prenum; Prenum = nchar - '0'; for (;;) { premsg(' ', NUL); nchar = vgetc(); State = NORMAL; if (nchar == DEL) Prenum /= 10; else if (isdigit(nchar)) Prenum = Prenum * 10 + (nchar - '0'); else if (nchar == CR) { win_setheight((int)Prenum); break; } else { CLEAROPBEEP; break; } } operator = NOP; break; } if (Prenum && Prenum != curwin->w_cursor.lnum) /* line number given */ { setpcmark(); if (Prenum > curbuf->b_ml.ml_line_count) curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; else curwin->w_cursor.lnum = Prenum; } State = NORMAL; /* for updateScreen() */ switch (nchar) { case NL: /* put curwin->w_cursor at top of screen */ case CR: beginline(TRUE); case 't': curwin->w_topline = curwin->w_cursor.lnum; break; case '.': /* put curwin->w_cursor in middle of screen */ case 'z': n = (curwin->w_height + plines(curwin->w_cursor.lnum)) / 2; goto dozcmd; case '-': /* put curwin->w_cursor at bottom of screen */ case 'b': n = curwin->w_height; /* FALLTHROUGH */ dozcmd: { register linenr_t lp = curwin->w_cursor.lnum; register long l = plines(lp); do { curwin->w_topline = lp; if (--lp == 0) break; l += plines(lp); } while (l <= n); } if (nchar != 'z' && nchar != 'b') beginline(TRUE); break; case Ctrl('S'): /* ignore CTRL-S and CTRL-Q to avoid problems */ case Ctrl('Q'): /* with terminals that use xon/xoff */ break; default: CLEAROPBEEP; } updateScreen(VALID); break; /* * 2: Control commands */ case ':': if (VIsual.lnum) goto dooperator; CHECKCLEAROP; /* * translate "count:" into ":.,.+(count - 1)" */ if (Prenum) { stuffReadbuff((char_u *)"."); if (Prenum > 1) { stuffReadbuff((char_u *)",.+"); stuffnumReadbuff((long)Prenum - 1L); } } docmdline(NULL); modified = TRUE; break; case K_HELP: CHECKCLEAROP; help(); break; case Ctrl('L'): CHECKCLEAROP; updateScreen(CLEAR); break; case Ctrl('G'): CHECKCLEAROP; fileinfo(did_cd || Prenum); /* print full name if count given or :cd used */ break; case K_CCIRCM: /* CTRL-^, short for ":e #" */ CHECKCLEAROPQ; (void)buflist_getfile((int)Prenum, (linenr_t)0, TRUE); break; case 'Z': /* write, if changed, and exit */ CHECKCLEAROPQ; if (nchar != 'Z') { CLEAROPBEEP; break; } stuffReadbuff((char_u *)":x\n"); break; case Ctrl(']'): /* :ta to current identifier */ CHECKCLEAROPQ; case '*': /* / to current identifier or string */ case '#': /* ? to current identifier or string */ case 'K': /* run program for current identifier */ { register int col; register int i; /* * if i == 0: try to find an identifier * if i == 1: try to find any string */ ptr = ml_get(curwin->w_cursor.lnum); for (i = 0; i < 2; ++i) { /* * skip to start of identifier/string */ col = curwin->w_cursor.col; while (ptr[col] != NUL && (i == 0 ? !isidchar(ptr[col]) : iswhite(ptr[col]))) ++col; /* * Back up to start of identifier/string. This doesn't match the * real vi but I like it a little better and it shouldn't bother * anyone. */ while (col > 0 && (i == 0 ? isidchar(ptr[col - 1]) : (!iswhite(ptr[col - 1]) && !isidchar(ptr[col - 1])))) --col; /* * if identifier found or not '*' or '#' command, stop searching */ if (isidchar(ptr[col]) || (c != '*' && c != '#')) break; } /* * did't find an identifier of string */ if (ptr[col] == NUL || (!isidchar(ptr[col]) && i == 0)) { CLEAROPBEEP; break; } if (Prenum) stuffnumReadbuff(Prenum); switch (c) { case '*': stuffReadbuff((char_u *)"/"); goto sow; case '#': stuffReadbuff((char_u *)"?"); sow: if (i == 0) stuffReadbuff((char_u *)"\\<"); break; case 'K': stuffReadbuff((char_u *)":! "); stuffReadbuff(p_kp); stuffReadbuff((char_u *)" "); break; default: stuffReadbuff((char_u *)":ta "); } /* * Now grab the chars in the identifier */ while (i == 0 ? isidchar(ptr[col]) : (ptr[col] != NUL && !iswhite(ptr[col]))) { stuffcharReadbuff(ptr[col]); ++col; } if ((c == '*' || c == '#') && i == 0) stuffReadbuff((char_u *)"\\>"); stuffReadbuff((char_u *)"\n"); } break; case Ctrl('T'): /* backwards in tag stack */ CHECKCLEAROPQ; dotag((char_u *)"", 2, (int)Prenum1); break; /* * Cursor motions */ case 'G': mtype = MLINE; setpcmark(); if (Prenum == 0 || Prenum > curbuf->b_ml.ml_line_count) curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; else curwin->w_cursor.lnum = Prenum; beginline(TRUE); break; case 'H': case 'M': if (c == 'M') n = (curwin->w_height - curwin->w_empty_rows) / 2; else n = Prenum; mtype = MLINE; setpcmark(); curwin->w_cursor.lnum = curwin->w_topline; while (n && onedown((long)1) == OK) --n; beginline(TRUE); break; case 'L': mtype = MLINE; setpcmark(); curwin->w_cursor.lnum = curwin->w_botline - 1; for (n = Prenum; n && oneup((long)1) == OK; n--) ; beginline(TRUE); break; case 'l': case K_RARROW: case ' ': mtype = MCHAR; mincl = FALSE; n = Prenum1; while (n--) { if (oneright() == FAIL) { /* space wraps to next line if 'whichwrap' bit 1 set */ /* 'l' wraps to next line if 'whichwrap' bit 2 set */ /* CURS_RIGHT wraps to next line if 'whichwrap' bit 3 set */ if (((c == ' ' && (p_ww & 2)) || (c == 'l' && (p_ww & 4)) || (c == K_RARROW && (p_ww & 8))) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { ++curwin->w_cursor.lnum; curwin->w_cursor.col = 0; curwin->w_set_curswant = TRUE; continue; } if (operator == NOP) beep(); else { if (lineempty(curwin->w_cursor.lnum)) CLEAROPBEEP; else { mincl = TRUE; if (n) beep(); } } break; } } break; case Ctrl('H'): case 'h': case K_LARROW: case DEL: mtype = MCHAR; mincl = FALSE; n = Prenum1; while (n--) { if (oneleft() == FAIL) { /* backspace and del wrap to previous line if 'whichwrap' * bit 0 set */ /* 'h' wraps to previous line if 'whichwrap' bit 2 set */ /* CURS_LEFT wraps to previous line if 'whichwrap' bit 3 set */ if ((((c == Ctrl('H') || c == DEL) && (p_ww & 1)) || (c == 'h' && (p_ww & 4)) || (c == K_LARROW && (p_ww & 8))) && curwin->w_cursor.lnum > 1) { --(curwin->w_cursor.lnum); coladvance(MAXCOL); curwin->w_set_curswant = TRUE; continue; } else if (operator != DELETE && operator != CHANGE) beep(); else if (Prenum1 == 1) CLEAROPBEEP; break; } } break; case '-': flag = TRUE; /* FALLTHROUGH */ case 'k': case K_UARROW: case Ctrl('P'): mtype = MLINE; if (oneup(Prenum1) == FAIL) CLEAROPBEEP; else if (flag) beginline(TRUE); break; case '+': case CR: flag = TRUE; /* FALLTHROUGH */ case 'j': case K_DARROW: case Ctrl('N'): case NL: mtype = MLINE; if (onedown(Prenum1) == FAIL) CLEAROPBEEP; else if (flag) beginline(TRUE); break; /* * This is a strange motion command that helps make operators more * logical. It is actually implemented, but not documented in the * real 'vi'. This motion command actually refers to "the current * line". Commands like "dd" and "yy" are really an alternate form of * "d_" and "y_". It does accept a count, so "d3_" works to delete 3 * lines. */ case '_': lineop: mtype = MLINE; if (onedown((long)(Prenum1 - 1)) == FAIL) CLEAROPBEEP; if (operator != YANK) /* 'Y' does not move cursor */ beginline(TRUE); break; case '|': mtype = MCHAR; mincl = TRUE; beginline(FALSE); if (Prenum > 0) coladvance((colnr_t)(Prenum - 1)); curwin->w_curswant = (colnr_t)(Prenum - 1); /* keep curswant at the column where we wanted to go, not where we ended; differs is line is too short */ curwin->w_set_curswant = FALSE; break; /* * Word Motions */ case 'B': type = 1; /* FALLTHROUGH */ case 'b': case K_SLARROW: mtype = MCHAR; mincl = FALSE; curwin->w_set_curswant = TRUE; if (bck_word(Prenum1, type)) CLEAROPBEEP; break; case 'E': type = 1; /* FALLTHROUGH */ case 'e': mincl = TRUE; goto dowrdcmd; case 'W': type = 1; /* FALLTHROUGH */ case 'w': case K_SRARROW: mincl = FALSE; flag = TRUE; /* * This is a little strange. To match what the real vi does, we * effectively map 'cw' to 'ce', and 'cW' to 'cE', provided that we are * not on a space or a TAB. This seems * impolite at first, but it's really more what we mean when we say * 'cw'. * Another strangeness: When standing on the end of a word "ce" will * change until the end of the next wordt, but "cw" will change only * one character! This is done by setting type to 2. */ if (operator == CHANGE && (n = gchar_cursor()) != ' ' && n != TAB && n != NUL) { mincl = TRUE; flag = FALSE; flag2 = TRUE; } dowrdcmd: mtype = MCHAR; curwin->w_set_curswant = TRUE; if (flag) n = fwd_word(Prenum1, type, operator != NOP); else n = end_word(Prenum1, type, flag2); if (n) { CLEAROPBEEP; break; } #if 0 /* * If we do a 'dw' for the last word in a line, we only delete the rest * of the line, not joining the two lines, unless the current line is empty. */ if (operator == DELETE && Prenum1 == 1 && curbuf->b_startop.lnum != curwin->w_cursor.lnum && !lineempty(startop.lnum)) { curwin->w_cursor = curbuf->b_startop; while (oneright() == OK) ; mincl = TRUE; } #endif break; case '$': mtype = MCHAR; mincl = TRUE; curwin->w_curswant = MAXCOL; /* so we stay at the end */ if (onedown((long)(Prenum1 - 1)) == FAIL) { CLEAROPBEEP; break; } break; case '^': flag = TRUE; /* FALLTHROUGH */ case '0': mtype = MCHAR; mincl = FALSE; beginline(flag); break; /* * 4: Searches */ case '?': case '/': if (!getcmdline(c, searchbuff)) { CLEAROP; break; } mtype = MCHAR; mincl = FALSE; curwin->w_set_curswant = TRUE; n = dosearch(c, searchbuff, FALSE, Prenum1, TRUE, TRUE); if (n == 0) CLEAROP; else if (n == 2) mtype = MLINE; break; case 'N': flag = 1; case 'n': mtype = MCHAR; mincl = FALSE; curwin->w_set_curswant = TRUE; if (!dosearch(0, NULL, flag, Prenum1, TRUE, TRUE)) CLEAROP; break; /* * Character searches */ case 'T': dir = BACKWARD; /* FALLTHROUGH */ case 't': type = 1; goto docsearch; case 'F': dir = BACKWARD; /* FALLTHROUGH */ case 'f': docsearch: mtype = MCHAR; if (dir == BACKWARD) mincl = FALSE; else mincl = TRUE; curwin->w_set_curswant = TRUE; if (!searchc(nchar, dir, type, Prenum1)) CLEAROPBEEP; break; case ',': flag = 1; /* FALLTHROUGH */ case ';': dir = flag; goto docsearch; /* nchar == NUL, thus repeat previous search */ /* * section or C function searches */ case '[': dir = BACKWARD; /* FALLTHROUGH */ case ']': mtype = MCHAR; mincl = FALSE; /* * "[f" or "]f" : Edit file under the cursor (same as "gf") */ if ((c == ']' || c == '[') && nchar == 'f') goto gotofile; /* * "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')' */ if ((c == '[' && (nchar == '{' || nchar == '(')) || ((c == ']' && (nchar == '}' || nchar == ')')))) { FPOS old_pos; old_pos = curwin->w_cursor; while (Prenum1--) { if ((pos = showmatch(nchar)) == NULL) { CLEAROPBEEP; break; } curwin->w_cursor = *pos; } curwin->w_cursor = old_pos; if (pos != NULL) { setpcmark(); curwin->w_cursor = *pos; curwin->w_set_curswant = TRUE; } break; } /* * "[[", "[]", "]]" and "][": move to start or end of function */ if (nchar == '[' || nchar == ']') { if (nchar == c) /* "]]" or "[[" */ flag = '{'; else flag = '}'; /* "][" or "[]" */ curwin->w_set_curswant = TRUE; /* * Imitate strange vi behaviour: When using "]]" with an operator we * also stop at '}'. */ if (!findpar(dir, Prenum1, flag, (operator != NOP && dir == FORWARD && flag == '{'))) CLEAROPBEEP; break; } /* * "[p" and "]p": put with indent adjustment */ if (nchar == 'p') { doput((c == ']') ? FORWARD : BACKWARD, Prenum1, TRUE); modified = TRUE; break; } /* * end of '[' and ']': not a valid nchar */ CLEAROPBEEP; break; case '%': mincl = TRUE; if (Prenum) /* {cnt}% : goto {cnt} percentage in file */ { if (Prenum > 100) CLEAROPBEEP; else { mtype = MLINE; setpcmark(); /* round up, so CTRL-G will give same value */ curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count * Prenum + 99) / 100; beginline(TRUE); } } else /* % : go to matching paren */ { mtype = MCHAR; if ((pos = showmatch(NUL)) == NULL) CLEAROPBEEP; else { setpcmark(); curwin->w_cursor = *pos; curwin->w_set_curswant = TRUE; } } break; case '(': dir = BACKWARD; /* FALLTHROUGH */ case ')': mtype = MCHAR; if (c == ')') mincl = FALSE; else mincl = TRUE; curwin->w_set_curswant = TRUE; if (!findsent(dir, Prenum1)) CLEAROPBEEP; break; case '{': dir = BACKWARD; /* FALLTHROUGH */ case '}': mtype = MCHAR; mincl = FALSE; curwin->w_set_curswant = TRUE; if (!findpar(dir, Prenum1, NUL, FALSE)) CLEAROPBEEP; break; /* * 5: Edits */ case '.': CHECKCLEAROPQ; if (start_redo(Prenum) == FAIL) CLEAROPBEEP; modified = TRUE; break; case 'u': if (VIsual.lnum) goto dooperator; case K_UNDO: CHECKCLEAROPQ; u_undo((int)Prenum1); curwin->w_set_curswant = TRUE; modified = TRUE; break; case Ctrl('R'): CHECKCLEAROPQ; u_redo((int)Prenum1); curwin->w_set_curswant = TRUE; modified = TRUE; break; case 'U': if (VIsual.lnum) goto dooperator; CHECKCLEAROPQ; u_undoline(); curwin->w_set_curswant = TRUE; modified = TRUE; break; case 'r': if (VIsual.lnum) { c = 'c'; goto dooperator; } CHECKCLEAROPQ; ptr = ml_get_cursor(); if (STRLEN(ptr) < (unsigned)Prenum1) /* not enough characters to replace */ { CLEAROPBEEP; break; } /* * Replacing with a line break or tab is done by edit(), because it * is complicated. * Other characters are done below to avoid problems with things like * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC). */ if (nchar == '\r' || nchar == '\n' || nchar == '\t') { prep_redo(Prenum1, 'r', nchar, NUL); stuffnumReadbuff(Prenum1); stuffcharReadbuff('R'); stuffcharReadbuff(nchar); stuffcharReadbuff(ESC); break; } if (nchar == Ctrl('V')) /* get another character */ { c = Ctrl('V'); nchar = get_literal(&type); if (type) /* typeahead */ stuffcharReadbuff(type); } else c = NUL; prep_redo(Prenum1, 'r', c, nchar); if (!u_save_cursor()) /* save line for undo */ break; /* * Get ptr again, because u_save will have released the line. * At the same time we let know that the line will be changed. */ ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE) + curwin->w_cursor.col; curwin->w_cursor.col += Prenum1 - 1; while (Prenum1--) /* replace the characters */ *ptr++ = nchar; curwin->w_set_curswant = TRUE; CHANGED; updateline(); modified = TRUE; break; case 'J': if (VIsual.lnum) /* join the visual lines */ { if (curwin->w_cursor.lnum > VIsual.lnum) { Prenum = curwin->w_cursor.lnum - VIsual.lnum + 1; curwin->w_cursor.lnum = VIsual.lnum; } else Prenum = VIsual.lnum - curwin->w_cursor.lnum + 1; VIsual.lnum = 0; } CHECKCLEAROP; if (Prenum <= 1) Prenum = 2; /* default for join is two lines! */ if (curwin->w_cursor.lnum + Prenum - 1 > curbuf->b_ml.ml_line_count) /* beyond last line */ { CLEAROPBEEP; break; } prep_redo(Prenum, 'J', NUL, NUL); dodojoin(Prenum, TRUE, TRUE); modified = TRUE; break; case 'P': dir = BACKWARD; /* FALLTHROUGH */ case 'p': CHECKCLEAROPQ; prep_redo(Prenum, c, NUL, NUL); doput(dir, Prenum1, FALSE); modified = TRUE; break; case Ctrl('A'): /* add to number */ case Ctrl('X'): /* subtract from number */ CHECKCLEAROPQ; if (doaddsub((int)c, Prenum1) == OK) prep_redo(Prenum1, c, NUL, NUL); modified = TRUE; break; /* * 6: Inserts */ case 'A': curwin->w_set_curswant = TRUE; while (oneright() == OK) ; /* FALLTHROUGH */ case 'a': CHECKCLEAROPQ; /* Works just like an 'i'nsert on the next character. */ if (u_save_cursor()) { if (!lineempty(curwin->w_cursor.lnum)) inc_cursor(); startinsert(c, FALSE, Prenum1); modified = TRUE; command_busy = TRUE; } break; case 'I': beginline(TRUE); /* FALLTHROUGH */ case 'i': CHECKCLEAROPQ; if (u_save_cursor()) { startinsert(c, FALSE, Prenum1); modified = TRUE; command_busy = TRUE; } break; case 'o': if (VIsual.lnum) /* switch start and end of visual */ { Prenum = VIsual.lnum; VIsual.lnum = curwin->w_cursor.lnum; curwin->w_cursor.lnum = Prenum; if (VIsual.col != VISUALLINE) { n = VIsual.col; VIsual.col = curwin->w_cursor.col; curwin->w_cursor.col = (int)n; curwin->w_set_curswant = TRUE; } break; } CHECKCLEAROP; if (u_save(curwin->w_cursor.lnum, (linenr_t)(curwin->w_cursor.lnum + 1)) && Opencmd(FORWARD, TRUE, TRUE)) { startinsert('o', TRUE, Prenum1); modified = TRUE; command_busy = TRUE; } break; case 'O': CHECKCLEAROPQ; if (u_save((linenr_t)(curwin->w_cursor.lnum - 1), curwin->w_cursor.lnum) && Opencmd(BACKWARD, TRUE, TRUE)) { startinsert('O', TRUE, Prenum1); modified = TRUE; command_busy = TRUE; } break; case 'R': if (VIsual.lnum) { c = 'c'; VIsual.col = VISUALLINE; goto dooperator; } CHECKCLEAROPQ; if (u_save_cursor()) { startinsert('R', FALSE, Prenum1); modified = TRUE; command_busy = TRUE; } break; /* * 7: Operators */ case '~': /* swap case */ /* * if tilde is not an operator and Visual is off: swap case * of a single character */ if (!p_to && !VIsual.lnum) { CHECKCLEAROPQ; if (lineempty(curwin->w_cursor.lnum)) { CLEAROPBEEP; break; } prep_redo(Prenum, '~', NUL, NUL); if (!u_save_cursor()) break; for (; Prenum1 > 0; --Prenum1) { if (gchar_cursor() == NUL) break; swapchar(&curwin->w_cursor); inc_cursor(); } curwin->w_set_curswant = TRUE; CHANGED; updateline(); modified = TRUE; break; } /*FALLTHROUGH*/ case 'd': case 'c': case 'y': case '>': case '<': case '!': case '=': case 'Q': dooperator: n = STRCHR(opchars, c) - opchars + 1; if (n == operator) /* double operator works on lines */ goto lineop; CHECKCLEAROP; if (Prenum != 0) opnum = Prenum; curbuf->b_startop = curwin->w_cursor; operator = (int)n; break; /* * 8: Abbreviations */ /* when Visual the next commands are operators */ case 'S': case 'Y': case 'D': case 'C': case 'x': case 'X': case 's': if (VIsual.lnum) { static char_u trans[] = "ScYyDdCcxdXdsc"; if (isupper(c) && !Visual_block) /* uppercase means linewise */ VIsual.col = VISUALLINE; c = *(STRCHR(trans, c) + 1); goto dooperator; } case '&': CHECKCLEAROPQ; if (Prenum) stuffnumReadbuff(Prenum); if (c == 'Y' && p_ye) c = 'Z'; { static char_u *(ar[9]) = {(char_u *)"dl", (char_u *)"dh", (char_u *)"d$", (char_u *)"c$", (char_u *)"cl", (char_u *)"cc", (char_u *)"yy", (char_u *)"y$", (char_u *)":s\r"}; static char_u *str = (char_u *)"xXDCsSYZ&"; stuffReadbuff(ar[(int)(STRCHR(str, c) - str)]); } break; /* * 9: Marks */ case 'm': CHECKCLEAROP; if (setmark(nchar) == FAIL) CLEAROPBEEP; break; case '\'': flag = TRUE; /* FALLTHROUGH */ case '`': pos = getmark(nchar, (operator == NOP)); if (pos == (FPOS *)-1) /* jumped to other file */ { if (flag) beginline(TRUE); break; } if (pos != NULL) setpcmark(); cursormark: if (pos == NULL || pos->lnum == 0) CLEAROPBEEP; else { curwin->w_cursor = *pos; if (flag) beginline(TRUE); } mtype = flag ? MLINE : MCHAR; mincl = FALSE; /* ignored if not MCHAR */ curwin->w_set_curswant = TRUE; break; case Ctrl('O'): /* goto older pcmark */ Prenum1 = -Prenum1; /* FALLTHROUGH */ case Ctrl('I'): /* goto newer pcmark */ CHECKCLEAROPQ; pos = movemark((int)Prenum1); if (pos == (FPOS *)-1) /* jump to other file */ { curwin->w_set_curswant = TRUE; break; } goto cursormark; /* * 10. Buffer setting */ case '"': CHECKCLEAROP; if (nchar != NUL && is_yank_buffer(nchar, FALSE)) { yankbuffer = nchar; opnum = Prenum; /* remember count before '"' */ } else CLEAROPBEEP; break; /* * 11. Visual */ case 'v': case 'V': case Ctrl('V'): CHECKCLEAROP; Visual_block = FALSE; /* stop Visual */ if (VIsual.lnum) { VIsual.lnum = 0; updateScreen(NOT_VALID); /* delete the inversion */ } /* start Visual */ else { if (!didwarn && set_highlight('v') == FAIL)/* cannot highlight */ { EMSG("Warning: terminal cannot highlight"); didwarn = TRUE; } if (Prenum) /* use previously selected part */ { if (!resel_Visual_type) /* there is none */ { beep(); break; } VIsual = curwin->w_cursor; if (resel_Visual_nlines > 1) curwin->w_cursor.lnum += resel_Visual_nlines * Prenum - 1; switch (resel_Visual_type) { case 'V': VIsual.col = VISUALLINE; break; case Ctrl('V'): Visual_block = TRUE; break; case 'v': if (resel_Visual_nlines <= 1) curwin->w_cursor.col += resel_Visual_col * Prenum - 1; else curwin->w_cursor.col = resel_Visual_col; break; } if (resel_Visual_col == MAXCOL) { curwin->w_curswant = MAXCOL; coladvance(MAXCOL); } else if (Visual_block) coladvance((colnr_t)(curwin->w_virtcol + resel_Visual_col * Prenum - 1)); curs_columns(TRUE); /* recompute w_virtcol */ updateScreen(NOT_VALID); /* show the inversion */ } else { VIsual = curwin->w_cursor; if (c == 'V') /* linewise */ VIsual.col = VISUALLINE; else if (c == Ctrl('V')) /* blockwise */ Visual_block = TRUE; updateline(); /* start the inversion */ } } break; /* * 12. Suspend */ case Ctrl('Z'): CLEAROP; VIsual.lnum = 0; /* stop Visual */ stuffReadbuff((char_u *)":st\r"); /* with autowrite */ break; /* * 13. Window commands */ case Ctrl('W'): CHECKCLEAROP; do_window(nchar, Prenum); /* everything is in window.c */ break; /* * 14. extended commands (starting with 'g') */ case 'g': switch (nchar) { /* * "gf": goto file, edit file under cursor * "]f" and "[f": can also be used. */ case 'f': gotofile: ptr = file_name_at_cursor(); /* do autowrite if necessary */ if (curbuf->b_changed && curbuf->b_nwindows <= 1 && !p_hid) autowrite(curbuf); if (ptr != NULL) { setpcmark(); stuffReadbuff((char_u *) ":e "); stuffReadbuff(ptr); stuffReadbuff((char_u *) "\n"); free(ptr); } else CLEAROPBEEP; break; /* * "gs": goto sleep */ case 's': while (Prenum1-- && !got_int) { sleep(1); breakcheck(); } break; default: CLEAROPBEEP; break; } break; /* * The end */ case ESC: if (VIsual.lnum) { VIsual.lnum = 0; /* stop Visual */ updateScreen(NOT_VALID); CLEAROP; /* don't beep */ break; } /* Don't drop through and beep if we are canceling a command: */ else if (operator != NOP || opnum || Prenum || yankbuffer) { CLEAROP; /* don't beep */ break; } /* FALLTHROUGH */ default: /* not a known command */ CLEAROPBEEP; break; } /* end of switch on command character */ /* * if we didn't start or finish an operator, reset yankbuffer, unless we * need it later. */ if (!finish_op && !operator && strchr("\"DCYSsXx.", c) == NULL) yankbuffer = 0; /* * If an operation is pending, handle it... */ if ((VIsual.lnum || finish_op) && operator != NOP) { if (operator != YANK && !VIsual.lnum) /* can't redo yank */ { prep_redo(Prenum, opchars[operator - 1], c, nchar); if (c == '/' || c == '?') /* was a search */ { AppendToRedobuff(searchbuff); AppendToRedobuff(NL_STR); } } if (redo_Visual_busy) { curbuf->b_startop = curwin->w_cursor; curwin->w_cursor.lnum += redo_Visual_nlines - 1; switch (redo_Visual_type) { case 'V': VIsual.col = VISUALLINE; break; case Ctrl('V'): Visual_block = TRUE; break; case 'v': if (redo_Visual_nlines <= 1) curwin->w_cursor.col += redo_Visual_col - 1; else curwin->w_cursor.col = redo_Visual_col; break; } if (redo_Visual_col == MAXCOL) { curwin->w_curswant = MAXCOL; coladvance(MAXCOL); } Prenum = redo_Visual_Prenum; if (Prenum == 0) Prenum1 = 1L; else Prenum1 = Prenum; } else if (VIsual.lnum) curbuf->b_startop = VIsual; if (lt(curbuf->b_startop, curwin->w_cursor)) { curbuf->b_endop = curwin->w_cursor; curwin->w_cursor = curbuf->b_startop; } else { curbuf->b_endop = curbuf->b_startop; curbuf->b_startop = curwin->w_cursor; } nlines = curbuf->b_endop.lnum - curbuf->b_startop.lnum + 1; if (VIsual.lnum || redo_Visual_busy) { if (Visual_block) /* block mode */ { startvcol = getvcol(curwin, &(curbuf->b_startop), 2); n = getvcol(curwin, &(curbuf->b_endop), 2); if (n < startvcol) startvcol = (colnr_t)n; /* if '$' was used, get endvcol from longest line */ if (curwin->w_curswant == MAXCOL) { curwin->w_cursor.col = MAXCOL; endvcol = 0; for (curwin->w_cursor.lnum = curbuf->b_startop.lnum; curwin->w_cursor.lnum <= curbuf->b_endop.lnum; ++curwin->w_cursor.lnum) if ((n = getvcol(curwin, &curwin->w_cursor, 3)) > endvcol) endvcol = (colnr_t)n; curwin->w_cursor = curbuf->b_startop; } else if (redo_Visual_busy) endvcol = startvcol + redo_Visual_col - 1; else { endvcol = getvcol(curwin, &(curbuf->b_startop), 3); n = getvcol(curwin, &(curbuf->b_endop), 3); if (n > endvcol) endvcol = (colnr_t)n; } coladvance(startvcol); } /* * prepare to reselect and redo Visual: this is based on the size * of the Visual text */ if (Visual_block) resel_Visual_type = Ctrl('V'); else if (VIsual.col == VISUALLINE) resel_Visual_type = 'V'; else resel_Visual_type = 'v'; if (curwin->w_curswant == MAXCOL) resel_Visual_col = MAXCOL; else if (Visual_block) resel_Visual_col = endvcol - startvcol + 1; else if (nlines > 1) resel_Visual_col = curbuf->b_endop.col; else resel_Visual_col = curbuf->b_endop.col - curbuf->b_startop.col + 1; resel_Visual_nlines = nlines; if (operator != YANK && operator != COLON) /* can't redo yank and : */ { prep_redo(0L, 'v', opchars[operator - 1], NUL); redo_Visual_type = resel_Visual_type; redo_Visual_col = resel_Visual_col; redo_Visual_nlines = resel_Visual_nlines; redo_Visual_Prenum = Prenum; } /* * Mincl defaults to TRUE. * If endop is on a NUL (empty line) mincl becomes FALSE * This makes "d}P" and "v}dP" work the same. */ mincl = TRUE; if (VIsual.col == VISUALLINE) mtype = MLINE; else { mtype = MCHAR; if (*ml_get_pos(&(curbuf->b_endop)) == NUL) mincl = FALSE; } redo_Visual_busy = FALSE; /* * Switch Visual off now, so screen updating does * not show inverted text when the screen is redrawn. * With YANK and sometimes with COLON and FILTER there is no screen * redraw, so it is done here to remove the inverted part. */ VIsual.lnum = 0; if (operator == YANK || operator == COLON || operator == FILTER) updateScreen(NOT_VALID); } else if (operator == LSHIFT || operator == RSHIFT) Prenum1 = 1L; /* if not visual mode: shift one indent */ curwin->w_set_curswant = 1; /* no_op is set when start and end are the same */ no_op = (mtype == MCHAR && !mincl && equal(curbuf->b_startop, curbuf->b_endop)); /* * If the end of an operator is in column one while mtype is MCHAR and mincl * is FALSE, we put endop after the last character in the previous line. * If startop is on or before the first non-blank in the line, the operator * becomes linewise (strange, but that's the way vi does it). */ if (mtype == MCHAR && mincl == FALSE && curbuf->b_endop.col == 0 && nlines > 1) { --nlines; --curbuf->b_endop.lnum; if (inindent()) mtype = MLINE; else { curbuf->b_endop.col = STRLEN(ml_get(curbuf->b_endop.lnum)); if (curbuf->b_endop.col) { --curbuf->b_endop.col; mincl = TRUE; } } } switch (operator) { case LSHIFT: case RSHIFT: doshift(operator, TRUE, (int)Prenum1); modified = TRUE; break; case DELETE: if (!no_op) { dodelete(); modified = TRUE; } break; case YANK: if (!no_op) (void)doyank(FALSE); break; case CHANGE: dochange(); modified = TRUE; command_busy = TRUE; break; case FILTER: bangredo = TRUE; /* dobang() will put cmd in redo buffer */ case INDENT: case COLON: dofilter: sprintf((char *)IObuff, ":%ld,%ld", (long)curbuf->b_startop.lnum, (long)curbuf->b_endop.lnum); stuffReadbuff(IObuff); if (operator != COLON) stuffReadbuff((char_u *)"!"); if (operator == INDENT) { stuffReadbuff(p_ep); stuffReadbuff((char_u *)"\n"); } else if (operator == FORMAT) { stuffReadbuff(p_fp); stuffReadbuff((char_u *)"\n"); } /* docmdline() does the rest */ break; case TILDE: case UPPER: case LOWER: if (!no_op) { dotilde(); modified = TRUE; } break; case FORMAT: if (*p_fp != NUL) goto dofilter; /* use external command */ doformat(); /* use internal function */ modified = TRUE; break; default: CLEAROPBEEP; } operator = NOP; Visual_block = FALSE; yankbuffer = 0; } normal_end: premsg(-1, NUL); if (restart_edit && operator == NOP && VIsual.lnum == 0 && !command_busy && stuff_empty() && yankbuffer == 0) { startinsert(restart_edit, FALSE, 1L); modified = TRUE; } checkpcmark(); /* check if we moved since setting pcmark */ /* * TEMPORARY: update the other windows for the current buffer if modified */ if (modified) { WIN *wp; for (wp = firstwin; wp; wp = wp->w_next) if (wp != curwin && wp->w_buffer == curbuf) { cursor_off(); wp->w_redr_type = NOT_VALID; win_update(wp); } } }