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
[] = "@(#)v_mark.c 10.8 (Berkeley) 9/20/96";
16 #include <sys/types.h>
17 #include <sys/queue.h>
20 #include <bitstring.h>
25 #include "../common/common.h"
32 * PUBLIC: int v_mark __P((SCR *, VICMD *));
39 return (mark_set(sp
, vp
->character
, &vp
->m_start
, 1));
42 enum which
{BQMARK
, FQMARK
};
43 static int mark
__P((SCR
*, VICMD
*, enum which
));
50 * Moves to a mark, setting both row and column.
53 * Although not commonly known, the "'`" and "'`" forms are historically
54 * valid. The behavior is determined by the first character, so "`'" is
55 * the same as "``". Remember this fact -- you'll be amazed at how many
56 * people don't know it and will be delighted that you are able to tell
59 * PUBLIC: int v_bmark __P((SCR *, VICMD *));
66 return (mark(sp
, vp
, BQMARK
));
73 * Move to the first nonblank character of the line containing the mark.
75 * PUBLIC: int v_fmark __P((SCR *, VICMD *));
82 return (mark(sp
, vp
, FQMARK
));
99 if (mark_get(sp
, vp
->character
, &vp
->m_stop
, M_BERR
))
104 * Historically, BQMARKS for character positions that no longer
105 * existed acted as FQMARKS.
107 * FQMARKS move to the first non-blank.
111 if (db_get(sp
, vp
->m_stop
.lno
, DBG_FATAL
, NULL
, &len
))
113 if (vp
->m_stop
.cno
< len
||
114 vp
->m_stop
.cno
== len
&& len
== 0)
123 if (nonblank(sp
, vp
->m_stop
.lno
, &vp
->m_stop
.cno
))
130 /* Non-motion commands move to the end of the range. */
132 vp
->m_final
= vp
->m_stop
;
138 * If a motion component to a BQMARK, the cursor has to move.
141 vp
->m_stop
.lno
== vp
->m_start
.lno
&&
142 vp
->m_stop
.cno
== vp
->m_start
.cno
) {
148 * If the motion is in the reverse direction, switch the start and
149 * stop MARK's so that it's in a forward direction. (There's no
150 * reason for this other than to make the tests below easier. The
151 * code in vi.c:vi() would have done the switch.) Both forward
152 * and backward motions can happen for any kind of search command.
154 if (vp
->m_start
.lno
> vp
->m_stop
.lno
||
155 vp
->m_start
.lno
== vp
->m_stop
.lno
&&
156 vp
->m_start
.cno
> vp
->m_stop
.cno
) {
158 vp
->m_start
= vp
->m_stop
;
165 * Yank cursor motion, when associated with marks as motion commands,
166 * historically behaved as follows:
169 * Line change? Line change?
171 * -------------- ---------------
172 * FORWARD: | NM NM | NM NM
174 * BACKWARD: | M M | M NM(1)
176 * where NM means the cursor didn't move, and M means the cursor
179 * As the cursor was usually moved for yank commands associated
180 * with backward motions, this implementation regularizes it by
181 * changing the NM at position (1) to be an M. This makes mark
182 * motions match search motions, which is probably A Good Thing.
184 * Delete cursor motion was always to the start of the text region,
185 * regardless. Ignore other motion commands.
187 #ifdef HISTORICAL_PRACTICE
188 if (ISCMD(vp
->rkp
, 'y')) {
189 if ((cmd
== BQMARK
||
190 cmd
== FQMARK
&& vp
->m_start
.lno
!= vp
->m_stop
.lno
) &&
191 (vp
->m_start
.lno
> vp
->m_stop
.lno
||
192 vp
->m_start
.lno
== vp
->m_stop
.lno
&&
193 vp
->m_start
.cno
> vp
->m_stop
.cno
))
194 vp
->m_final
= vp
->m_stop
;
195 } else if (ISCMD(vp
->rkp
, 'd'))
196 if (vp
->m_start
.lno
> vp
->m_stop
.lno
||
197 vp
->m_start
.lno
== vp
->m_stop
.lno
&&
198 vp
->m_start
.cno
> vp
->m_stop
.cno
)
199 vp
->m_final
= vp
->m_stop
;
201 vp
->m_final
= vp
->m_start
;
205 * Forward marks are always line oriented, and it's set in the
212 * BQMARK'S moving backward and starting at column 0, and ones moving
213 * forward and ending at column 0 are corrected to the last column of
214 * the previous line. Otherwise, adjust the starting/ending point to
215 * the character before the current one (this is safe because we know
216 * the search had to move to succeed).
218 * Mark motions become line mode opertions if they start at the first
219 * nonblank and end at column 0 of another line.
221 if (vp
->m_start
.lno
< vp
->m_stop
.lno
&& vp
->m_stop
.cno
== 0) {
222 if (db_get(sp
, --vp
->m_stop
.lno
, DBG_FATAL
, NULL
, &len
))
224 vp
->m_stop
.cno
= len
? len
- 1 : 0;
226 if (nonblank(sp
, vp
->m_start
.lno
, &len
))
228 if (vp
->m_start
.cno
<= len
)