This is zle_vi.c in view mode; [Download] [Up]
/* * $Id: zle_vi.c,v 2.11 1996/10/15 20:16:35 hzoli Exp $ * * zle_vi.c - vi-specific functions * * This file is part of zsh, the Z shell. * * Copyright (c) 1992-1996 Paul Falstad * All rights reserved. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and to distribute modified versions of this software for any * purpose, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * In no event shall Paul Falstad or the Zsh Development Group be liable * to any party for direct, indirect, special, incidental, or consequential * damages arising out of the use of this software and its documentation, * even if Paul Falstad and the Zsh Development Group have been advised of * the possibility of such damage. * * Paul Falstad and the Zsh Development Group specifically disclaim any * warranties, including, but not limited to, the implied warranties of * merchantability and fitness for a particular purpose. The software * provided hereunder is on an "as is" basis, and Paul Falstad and the * Zsh Development Group have no obligation to provide maintenance, * support, updates, enhancements, or modifications. * */ #define ZLE #include "zsh.h" static int lastmult, lastbuf, lastgotmult, lastgotbuf, inrepeat, vichgrepeat; static void startvichange _((int im)); static void startvichange(int im) { if (im != -1) { insmode = im; vichgflag = 1; } if (inrepeat) { zmult = lastmult; vibufspec = lastbuf; gotmult = lastgotmult; gotvibufspec = lastgotbuf; inrepeat = vichgflag = 0; vichgrepeat = 1; } else { lastmult = zmult; lastbuf = vibufspec; lastgotmult = gotmult; lastgotbuf = gotvibufspec; if (vichgbuf) free(vichgbuf); vichgbuf = (char *)zalloc(vichgbufsz = 16); vichgbuf[0] = c; vichgbufptr = 1; vichgrepeat = 0; } } static void startvitext _((int im)); static void startvitext(int im) { startvichange(im); bindtab = mainbindtab; undoing = 0; viinsbegin = cs; } /**/ int vigetkey(void) { int cmd; if((c = getkey(0)) == EOF) { feep(); return -1; } cmd = mainbindtab[c]; if(cmd == z_prefix) { char buf[2]; Key ky; buf[0] = c; buf[1] = 0; ky = (Key) keybindtab->getnode(keybindtab, buf); if(!ky) cmd = z_undefinedkey; else cmd = ky->func; } if (cmd < 0 || cmd == z_sendbreak) { feep(); return -1; } else if (cmd == z_quotedinsert) { if ((c = getkey(0)) == EOF) { feep(); return -1; } } else if(cmd == z_viquotedinsert) { char sav = line[cs]; line[cs] = '^'; refresh(); c = getkey(0); line[cs] = sav; if(c == EOF) { feep(); return -1; } } else if (cmd == z_vicmdmode) return -1; return c; } /**/ int getvirange(int wf) { int k2, t0, startline, endline, obeep; int mult1, gotmult1; vilinerange = 0; startline = findbol(); endline = findeol(); /* get arguments for the command, and then the command key */ mult1 = zmult; gotmult1 = gotmult; zmult = 1; gotmult = 0; lastcmd &= ~(ZLE_NEGARG | ZLE_DIGIT); while(1) { if ((k2 = getkeycmd()) < 0 || k2 == z_sendbreak) { feep(); return -1; } if (!(zlecmds[k2].flags & ZLE_ARG)) break; (*zlecmds[k2].func) (); lastcmd = zlecmds[k2].flags; } /* double counts, such as in 3d4j, get multiplied, unless we're repeating */ if(vichgrepeat && gotmult1) { zmult = mult1; gotmult = 1; } else if (gotmult1) { zmult *= mult1; gotmult = 1; } /* can't handle an empty file */ if (!ll) { feep(); return -1; } /* This bit handles repeated command keys, such as dd. A number * * of lines is taken as the range. The current line is included. * * If the argument is positive, the lines go downward, otherwise * * vice versa. The argument gives the number of lines. */ if (k2 == bindk) { vilinerange = 1; if (!zmult) { feep(); return -1; } t0 = cs; if (zmult > 0) { while(zmult-- && cs <= ll) cs = findeol() + 1; if (zmult != -1) { cs = t0; feep(); return -1; } t0 = cs - 1; cs = startline; return t0; } else { while(zmult++ && cs >= 0) cs = findbol() - 1; if (zmult != 1) { cs = t0; feep(); return -1; } cs++; return endline; } } /* Not a movement?! No, you can't do yd. */ if (!(zlecmds[k2].flags & ZLE_MOVEMENT)) { feep(); return -1; } /* Now we need to execute the movement command, to see where it * * actually goes. virangeflag here indicates to the movement * * function that it should place the cursor at the end of the * * range, rather than where the cursor would actually go if it * * were executed normally. This makes a difference to some * * commands, but not all. For example, if searching forward * * for a character, under normal circumstances the cursor lands * * on the character. For a range, the range must include the * * character, so the cursor gets placed after the character if * * virangeflag is set. vi-match-bracket needs to change the * * value of virangeflag under some circumstances, meaning that * * we need to change the *starting* position. */ t0 = cs; virangeflag = 1; wordflag = wf; obeep = opts[BEEP]; opts[BEEP] = 0; (*zlecmds[k2].func) (); wordflag = 0; opts[BEEP] = obeep; if (cs == t0) { /* An error occured -- couldn't move. The movement command didn't * * feep, because we set NO_BEEP for the duration of the command. */ feep(); virangeflag = 0; return -1; } if(virangeflag == -1) t0++; virangeflag = 0; /* get the range the right way round */ if (cs > t0) { int tmp = cs; cs = t0; t0 = tmp; } /* Was it a line-oriented move? In this case, entire lines are taken. * * The terminating newline is left out of the range, which the real * * command must deal with appropriately. At this point we just need * * to make the range encompass entire lines. */ if (zlecmds[k2].flags & ZLE_LINEMOVE) { int newcs = findbol(); cs = t0; t0 = findeol(); cs = newcs; vilinerange = 1; } return t0; } /**/ void viaddnext(void) { if (cs != findeol()) cs++; startvitext(1); } /**/ void viaddeol(void) { cs = findeol(); startvitext(1); } /**/ void viinsert(void) { startvitext(1); } /**/ void viinsertbol(void) { vifirstnonblank(); startvitext(1); } /**/ void videlete(void) { int c2; startvichange(1); if ((c2 = getvirange(0)) != -1) { forekill(c2 - cs, 0); if (vilinerange && ll) { if (cs == ll) cs--; foredel(1); vifirstnonblank(); } } vichgflag = vilinerange = 0; } /**/ void videletechar(void) { startvichange(-1); /* handle negative argument */ if (zmult < 0) { zmult = -zmult; vibackwarddeletechar(); return; } /* it is an error to be on the end of line */ if (cs == ll || line[cs] == '\n') { feep(); return; } /* Put argument into the acceptable range -- it is not an error to * * specify a greater count than the number of available characters. */ if (zmult > findeol() - cs) zmult = findeol() - cs; /* do the deletion */ forekill(zmult, 0); } /**/ void vichange(void) { int c2; startvichange(1); if ((c2 = getvirange(1)) != -1) { forekill(c2 - cs, 0); bindtab = mainbindtab; viinsbegin = cs; undoing = 0; } vilinerange = 0; } /**/ void visubstitute(void) { startvichange(1); if (zmult < 0) { feep(); return; } /* it is an error to be on the end of line */ if (cs == ll || line[cs] == '\n') { feep(); return; } /* Put argument into the acceptable range -- it is not an error to * * specify a greater count than the number of available characters. */ if (zmult > findeol() - cs) zmult = findeol() - cs; /* do the substitution */ forekill(zmult, 0); startvitext(1); } /**/ void vichangeeol(void) { forekill(findeol() - cs, 0); startvitext(1); } /**/ void vichangewholeline(void) { vifirstnonblank(); vichangeeol(); } /**/ void viyank(void) { int oldcs = cs, c2; startvichange(1); if ((c2 = getvirange(0)) != -1) cut(cs, c2 - cs, 0); vichgflag = vilinerange = 0; cs = oldcs; } /**/ void viyankeol(void) { int x = findeol(); startvichange(-1); if (x == cs) { feep(); return; } cut(cs, x - cs, 0); } /**/ void viyankwholeline(void) { int bol = findbol(), oldcs = cs; startvichange(-1); if (zmult < 1) return; while(zmult--) { if (cs > ll) { feep(); cs = oldcs; return; } cs = findeol() + 1; } vilinerange = 1; cut(bol, cs - bol - 1, 0); cs = oldcs; } /**/ void vireplace(void) { startvitext(0); } /* vi-replace-chars has some oddities relating to vi-repeat-change. In * * the real vi, if one does 3r at the end of a line, it feeps without * * reading the argument. A successful rx followed by 3. at the end of * * a line (or 3rx followed by . at the end of a line) will obviously * * feep after the ., even though it has the argument available. Here * * repeating is tied very closely to argument reading, such that we * * can't do that. The solution is to just read the argument even if * * the command will fail -- not exactly vi compatible, but it is more * * consistent (consider dd in an empty file in vi). */ /**/ void vireplacechars(void) { int ch; startvichange(1); /* get key */ if((ch = vigetkey()) == -1) { vichgflag = 0; feep(); return; } /* check argument range */ if (zmult < 0 || zmult + cs > findeol()) { vichgflag = 0; feep(); return; } /* do change */ if (ch == '\r' || ch == '\n') { /* <return> handled specially */ cs += zmult - 1; backkill(zmult - 1, 0); line[cs++] = '\n'; } else { while (zmult--) line[cs++] = ch; cs--; } vichgflag = 0; } /**/ void vicmdmode(void) { if (bindtab == altbindtab) feep(); else { bindtab = altbindtab; undoing = 1; vichgflag = 0; if (cs != findbol()) cs--; } } /**/ void viopenlinebelow(void) { cs = findeol(); spaceinline(1); line[cs++] = '\n'; startvitext(1); } /**/ void viopenlineabove(void) { cs = findbol(); spaceinline(1); line[cs] = '\n'; startvitext(1); } /**/ void vioperswapcase(void) { int oldcs, c2; /* get the range */ startvichange(1); if ((c2 = getvirange(0)) != -1) { oldcs = cs; /* swap the case of all letters within range */ while (cs < c2) { if (islower(line[cs])) line[cs] = tuupper(line[cs]); else if (isupper(line[cs])) line[cs] = tulower(line[cs]); cs++; } /* go back to the first line of the range */ cs = oldcs; vifirstnonblank(); } vichgflag = vilinerange = 0; } /**/ void virepeatchange(void) { /* make sure we have a change to repeat */ if (!vichgbuf || vichgflag) { feep(); return; } /* restore or update the saved count and buffer */ if (gotmult) { lastmult = zmult; lastgotmult = 1; } if (gotvibufspec) { lastbuf = vibufspec; lastgotbuf = 1; } /* repeat the command */ inrepeat = 1; ungetkeys(vichgbuf, vichgbufptr); } /**/ void viindent(void) { int oldcs = cs, c2; /* get the range */ startvichange(1); if ((c2 = getvirange(0)) == -1) { vichgflag = vilinerange = 0; return; } vichgflag = 0; /* must be a line range */ if (!vilinerange) { feep(); cs = oldcs; return; } vilinerange = 0; oldcs = cs; /* add a tab to the beginning of each line within range */ while (cs < c2) { spaceinline(1); line[cs] = '\t'; cs = findeol() + 1; } /* go back to the first line of the range */ cs = oldcs; vifirstnonblank(); } /**/ void viunindent(void) { int oldcs = cs, c2; /* get the range */ startvichange(1); if ((c2 = getvirange(0)) == -1) { vichgflag = vilinerange = 0; return; } vichgflag = 0; /* must be a line range */ if (!vilinerange) { feep(); cs = oldcs; return; } vilinerange = 0; oldcs = cs; /* remove a tab from the beginning of each line within range */ while (cs < c2) { if (line[cs] == '\t') foredel(1); cs = findeol() + 1; } /* go back to the first line of the range */ cs = oldcs; vifirstnonblank(); } /**/ void vibackwarddeletechar(void) { if (bindtab == altbindtab) startvichange(-1); /* handle negative argument */ if (zmult < 0) { zmult = -zmult; videletechar(); return; } /* It is an error to be at the beginning of the line, or (in * * insert mode) to delete past the beginning of insertion. */ if ((bindtab != altbindtab && cs - zmult < viinsbegin) || cs == findbol()) { feep(); return; } /* Put argument into the acceptable range -- it is not an error to * * specify a greater count than the number of available characters. */ if (zmult > cs - findbol()) zmult = cs - findbol(); /* do the deletion */ backkill(zmult, 1); } /**/ void vikillline(void) { if (viinsbegin > cs) { feep(); return; } backdel(cs - viinsbegin); } /**/ void viputbefore(void) { Cutbuffer buf = &cutbuf; startvichange(-1); if (zmult < 0) return; if (gotvibufspec) buf = &vibuf[vibufspec]; if (!buf->buf) { feep(); return; } vilinerange = !!(buf->flags & CUTBUFFER_LINE); if (vilinerange) { cs = findbol(); spaceinline(buf->len + 1); memcpy((char *)line + cs, buf->buf, buf->len); line[cs + buf->len] = '\n'; vifirstnonblank(); } else { while (zmult--) { spaceinline(buf->len); memcpy((char *)line + cs, buf->buf, buf->len); cs += buf->len; } if (cs) cs--; } } /**/ void viputafter(void) { Cutbuffer buf = &cutbuf; startvichange(-1); if (zmult < 0) return; if (gotvibufspec) buf = &vibuf[vibufspec]; if (!buf->buf) { feep(); return; } vilinerange = !!(buf->flags & CUTBUFFER_LINE); if (vilinerange) { cs = findeol(); spaceinline(buf->len + 1); line[cs++] = '\n'; memcpy((char *)line + cs, buf->buf, buf->len); vifirstnonblank(); } else { if (cs != findeol()) cs++; while (zmult--) { spaceinline(buf->len); memcpy((char *)line + cs, buf->buf, buf->len); cs += buf->len; } if (cs) cs--; } } /**/ void vijoin(void) { int x; startvichange(-1); if ((x = findeol()) == ll) { feep(); return; } cs = x + 1; for (x = 1; cs != ll && iblank(line[cs]); cs++, x++); backdel(x); if (cs && iblank(line[cs-1])) cs--; else { spaceinline(1); line[cs] = ' '; } } /**/ void viswapcase(void) { int eol; startvichange(-1); if (zmult < 1) return; eol = findeol(); while (cs < eol && zmult--) { if (islower(line[cs])) line[cs] = tuupper(line[cs]); else if (isupper(line[cs])) line[cs] = tulower(line[cs]); cs++; } if (cs && cs == eol) cs--; } /**/ void vicapslockpanic(void) { feep(); statusline = "press a lowercase key to continue"; statusll = strlen(statusline); refresh(); while (!islower(getkey(0))); statusline = NULL; } /**/ void visetbuffer(void) { int ch; if (gotvibufspec || (((ch = getkey(0)) < '1' || ch > '9') && (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z'))) { feep(); return; } if (ch >= 'A' && ch <= 'Z') /* needed in cut() */ vibufappend = 1; else vibufappend = 0; vibufspec = tulower(ch) + (idigit(ch) ? -'1' + 26 : -'a'); gotvibufspec = 1; } /**/ void vikilleol(void) { int n = findeol() - cs; startvichange(-1); if (!n) { /* error -- line already empty */ feep(); return; } /* delete to end of line */ forekill(findeol() - cs, 0); } /**/ void vipoundinsert(void) { int oldcs = cs; startvichange(-1); vifirstnonblank(); if(line[cs] != '#') { spaceinline(1); line[cs] = '#'; if(cs <= viinsbegin) viinsbegin++; cs = oldcs + (cs <= oldcs); } else { foredel(1); if (cs < viinsbegin) viinsbegin--; cs = oldcs - (cs < oldcs); } } /**/ void viquotedinsert(void) { #ifndef HAS_TIO struct sgttyb sob; #endif spaceinline(1); line[cs] = '^'; refresh(); #ifndef HAS_TIO sob = shttyinfo.sgttyb; sob.sg_flags = (sob.sg_flags | RAW) & ~ECHO; ioctl(SHTTY, TIOCSETN, &sob); #endif c = getkey(0); #ifndef HAS_TIO setterm(); #endif foredel(1); if(c < 0) feep(); else selfinsert(); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.