diff options
Diffstat (limited to 'contrib/nvi/vi/v_mark.c')
-rw-r--r-- | contrib/nvi/vi/v_mark.c | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/contrib/nvi/vi/v_mark.c b/contrib/nvi/vi/v_mark.c new file mode 100644 index 0000000..447430e --- /dev/null +++ b/contrib/nvi/vi/v_mark.c @@ -0,0 +1,234 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. + * + * See the LICENSE file for redistribution information. + */ + +#include "config.h" + +#ifndef lint +static const char sccsid[] = "@(#)v_mark.c 10.8 (Berkeley) 9/20/96"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <bitstring.h> +#include <limits.h> +#include <stdlib.h> +#include <stdio.h> + +#include "../common/common.h" +#include "vi.h" + +/* + * v_mark -- m[a-z] + * Set a mark. + * + * PUBLIC: int v_mark __P((SCR *, VICMD *)); + */ +int +v_mark(sp, vp) + SCR *sp; + VICMD *vp; +{ + return (mark_set(sp, vp->character, &vp->m_start, 1)); +} + +enum which {BQMARK, FQMARK}; +static int mark __P((SCR *, VICMD *, enum which)); + + +/* + * v_bmark -- `['`a-z] + * Move to a mark. + * + * Moves to a mark, setting both row and column. + * + * !!! + * Although not commonly known, the "'`" and "'`" forms are historically + * valid. The behavior is determined by the first character, so "`'" is + * the same as "``". Remember this fact -- you'll be amazed at how many + * people don't know it and will be delighted that you are able to tell + * them. + * + * PUBLIC: int v_bmark __P((SCR *, VICMD *)); + */ +int +v_bmark(sp, vp) + SCR *sp; + VICMD *vp; +{ + return (mark(sp, vp, BQMARK)); +} + +/* + * v_fmark -- '['`a-z] + * Move to a mark. + * + * Move to the first nonblank character of the line containing the mark. + * + * PUBLIC: int v_fmark __P((SCR *, VICMD *)); + */ +int +v_fmark(sp, vp) + SCR *sp; + VICMD *vp; +{ + return (mark(sp, vp, FQMARK)); +} + +/* + * mark -- + * Mark commands. + */ +static int +mark(sp, vp, cmd) + SCR *sp; + VICMD *vp; + enum which cmd; +{ + dir_t dir; + MARK m; + size_t len; + + if (mark_get(sp, vp->character, &vp->m_stop, M_BERR)) + return (1); + + /* + * !!! + * Historically, BQMARKS for character positions that no longer + * existed acted as FQMARKS. + * + * FQMARKS move to the first non-blank. + */ + switch (cmd) { + case BQMARK: + if (db_get(sp, vp->m_stop.lno, DBG_FATAL, NULL, &len)) + return (1); + if (vp->m_stop.cno < len || + vp->m_stop.cno == len && len == 0) + break; + + if (ISMOTION(vp)) + F_SET(vp, VM_LMODE); + cmd = FQMARK; + /* FALLTHROUGH */ + case FQMARK: + vp->m_stop.cno = 0; + if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno)) + return (1); + break; + default: + abort(); + } + + /* Non-motion commands move to the end of the range. */ + if (!ISMOTION(vp)) { + vp->m_final = vp->m_stop; + return (0); + } + + /* + * !!! + * If a motion component to a BQMARK, the cursor has to move. + */ + if (cmd == BQMARK && + vp->m_stop.lno == vp->m_start.lno && + vp->m_stop.cno == vp->m_start.cno) { + v_nomove(sp); + return (1); + } + + /* + * If the motion is in the reverse direction, switch the start and + * stop MARK's so that it's in a forward direction. (There's no + * reason for this other than to make the tests below easier. The + * code in vi.c:vi() would have done the switch.) Both forward + * and backward motions can happen for any kind of search command. + */ + if (vp->m_start.lno > vp->m_stop.lno || + vp->m_start.lno == vp->m_stop.lno && + vp->m_start.cno > vp->m_stop.cno) { + m = vp->m_start; + vp->m_start = vp->m_stop; + vp->m_stop = m; + dir = BACKWARD; + } else + dir = FORWARD; + + /* + * Yank cursor motion, when associated with marks as motion commands, + * historically behaved as follows: + * + * ` motion ' motion + * Line change? Line change? + * Y N Y N + * -------------- --------------- + * FORWARD: | NM NM | NM NM + * | | + * BACKWARD: | M M | M NM(1) + * + * where NM means the cursor didn't move, and M means the cursor + * moved to the mark. + * + * As the cursor was usually moved for yank commands associated + * with backward motions, this implementation regularizes it by + * changing the NM at position (1) to be an M. This makes mark + * motions match search motions, which is probably A Good Thing. + * + * Delete cursor motion was always to the start of the text region, + * regardless. Ignore other motion commands. + */ +#ifdef HISTORICAL_PRACTICE + if (ISCMD(vp->rkp, 'y')) { + if ((cmd == BQMARK || + cmd == FQMARK && vp->m_start.lno != vp->m_stop.lno) && + (vp->m_start.lno > vp->m_stop.lno || + vp->m_start.lno == vp->m_stop.lno && + vp->m_start.cno > vp->m_stop.cno)) + vp->m_final = vp->m_stop; + } else if (ISCMD(vp->rkp, 'd')) + if (vp->m_start.lno > vp->m_stop.lno || + vp->m_start.lno == vp->m_stop.lno && + vp->m_start.cno > vp->m_stop.cno) + vp->m_final = vp->m_stop; +#else + vp->m_final = vp->m_start; +#endif + + /* + * Forward marks are always line oriented, and it's set in the + * vcmd.c table. + */ + if (cmd == FQMARK) + return (0); + + /* + * BQMARK'S moving backward and starting at column 0, and ones moving + * forward and ending at column 0 are corrected to the last column of + * the previous line. Otherwise, adjust the starting/ending point to + * the character before the current one (this is safe because we know + * the search had to move to succeed). + * + * Mark motions become line mode opertions if they start at the first + * nonblank and end at column 0 of another line. + */ + if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) { + if (db_get(sp, --vp->m_stop.lno, DBG_FATAL, NULL, &len)) + return (1); + vp->m_stop.cno = len ? len - 1 : 0; + len = 0; + if (nonblank(sp, vp->m_start.lno, &len)) + return (1); + if (vp->m_start.cno <= len) + F_SET(vp, VM_LMODE); + } else + --vp->m_stop.cno; + + return (0); +} |