2 * Copyright (c) 1992, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1992, 1993, 1994, 1995, 1996
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
13 static const char sccsid[] = "$Id: v_mark.c,v 10.12 2001/06/25 15:19:32 skimo Exp $";
16 #include <sys/types.h>
17 #include <sys/queue.h>
20 #include <bitstring.h>
25 #include "../common/common.h"
28 enum which {BQMARK, FQMARK};
29 static int mark(SCR *, VICMD *, int, enum which);
35 * PUBLIC: int v_mark(SCR *, VICMD *);
38 v_mark(SCR *sp, VICMD *vp)
40 return (mark_set(sp, vp->character, &vp->m_start, 1));
47 * Moves to a mark, setting both row and column.
50 * Although not commonly known, the "'`" and "'`" forms are historically
51 * valid. The behavior is determined by the first character, so "`'" is
52 * the same as "``". Remember this fact -- you'll be amazed at how many
53 * people don't know it and will be delighted that you are able to tell
56 * PUBLIC: int v_bmark(SCR *, VICMD *);
59 v_bmark(SCR *sp, VICMD *vp)
61 return (mark(sp, vp, 1, BQMARK));
68 * Move to the first nonblank character of the line containing the mark.
70 * PUBLIC: int v_fmark(SCR *, VICMD *);
73 v_fmark(SCR *sp, VICMD *vp)
75 return (mark(sp, vp, 1, FQMARK));
79 * v_emark -- <mouse click>
82 * PUBLIC: int v_emark(SCR *, VICMD *);
85 v_emark(SCR *sp, VICMD *vp)
89 smp = HMAP + vp->ev.e_lno;
91 msgq(sp, M_BERR, "320|Unknown cursor position.");
94 vp->m_stop.lno = smp->lno;
96 vs_colpos(sp, smp->lno, vp->ev.e_cno + (smp->soff - 1) * sp->cols);
97 return (mark(sp, vp, 0, BQMARK));
105 mark(SCR *sp, VICMD *vp, int getmark, enum which cmd)
111 if (getmark && mark_get(sp, vp->character, &vp->m_stop, M_BERR))
116 * Historically, BQMARKS for character positions that no longer
117 * existed acted as FQMARKS.
119 * FQMARKS move to the first non-blank.
123 if (db_get(sp, vp->m_stop.lno, DBG_FATAL, NULL, &len))
125 if (vp->m_stop.cno < len ||
126 (vp->m_stop.cno == len && len == 0))
135 if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno))
142 /* Non-motion commands move to the end of the range. */
144 vp->m_final = vp->m_stop;
150 * If a motion component to a BQMARK, the cursor has to move.
153 vp->m_stop.lno == vp->m_start.lno &&
154 vp->m_stop.cno == vp->m_start.cno) {
160 * If the motion is in the reverse direction, switch the start and
161 * stop MARK's so that it's in a forward direction. (There's no
162 * reason for this other than to make the tests below easier. The
163 * code in vi.c:vi() would have done the switch.) Both forward
164 * and backward motions can happen for any kind of search command.
166 if (vp->m_start.lno > vp->m_stop.lno ||
167 (vp->m_start.lno == vp->m_stop.lno &&
168 vp->m_start.cno > vp->m_stop.cno)) {
170 vp->m_start = vp->m_stop;
177 * Yank cursor motion, when associated with marks as motion commands,
178 * historically behaved as follows:
181 * Line change? Line change?
183 * -------------- ---------------
184 * FORWARD: | NM NM | NM NM
186 * BACKWARD: | M M | M NM(1)
188 * where NM means the cursor didn't move, and M means the cursor
191 * As the cursor was usually moved for yank commands associated
192 * with backward motions, this implementation regularizes it by
193 * changing the NM at position (1) to be an M. This makes mark
194 * motions match search motions, which is probably A Good Thing.
196 * Delete cursor motion was always to the start of the text region,
197 * regardless. Ignore other motion commands.
199 vp->m_final = vp->m_start;
202 * Forward marks are always line oriented, and it's set in the
209 * BQMARK'S moving backward and starting at column 0, and ones moving
210 * forward and ending at column 0 are corrected to the last column of
211 * the previous line. Otherwise, adjust the starting/ending point to
212 * the character before the current one (this is safe because we know
213 * the search had to move to succeed).
215 * Mark motions become line mode opertions if they start at the first
216 * nonblank and end at column 0 of another line.
218 if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) {
219 if (db_get(sp, --vp->m_stop.lno, DBG_FATAL, NULL, &len))
221 vp->m_stop.cno = len ? len - 1 : 0;
223 if (nonblank(sp, vp->m_start.lno, &len))
225 if (vp->m_start.cno <= len)