]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/nvi/vi/v_mark.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / nvi / vi / v_mark.c
1 /*-
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.
6  *
7  * See the LICENSE file for redistribution information.
8  */
9
10 #include "config.h"
11
12 #ifndef lint
13 static const char sccsid[] = "$Id: v_mark.c,v 10.12 2001/06/25 15:19:32 skimo Exp $";
14 #endif /* not lint */
15
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
19
20 #include <bitstring.h>
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24
25 #include "../common/common.h"
26 #include "vi.h"
27
28 enum which {BQMARK, FQMARK};
29 static int mark __P((SCR *, VICMD *, int, enum which));
30
31 /*
32  * v_mark -- m[a-z]
33  *      Set a mark.
34  *
35  * PUBLIC: int v_mark __P((SCR *, VICMD *));
36  */
37 int
38 v_mark(SCR *sp, VICMD *vp)
39 {
40         return (mark_set(sp, vp->character, &vp->m_start, 1));
41 }
42
43 /*
44  * v_bmark -- `['`a-z]
45  *      Move to a mark.
46  *
47  * Moves to a mark, setting both row and column.
48  *
49  * !!!
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
54  * them.
55  *
56  * PUBLIC: int v_bmark __P((SCR *, VICMD *));
57  */
58 int
59 v_bmark(SCR *sp, VICMD *vp)
60 {
61         return (mark(sp, vp, 1, BQMARK));
62 }
63
64 /*
65  * v_fmark -- '['`a-z]
66  *      Move to a mark.
67  *
68  * Move to the first nonblank character of the line containing the mark.
69  *
70  * PUBLIC: int v_fmark __P((SCR *, VICMD *));
71  */
72 int
73 v_fmark(SCR *sp, VICMD *vp)
74 {
75         return (mark(sp, vp, 1, FQMARK));
76 }
77
78 /*
79  * v_emark -- <mouse click>
80  *      Mouse mark.
81  *
82  * PUBLIC: int v_emark __P((SCR *, VICMD *));
83  */
84 int
85 v_emark(SCR *sp, VICMD *vp)
86 {
87         SMAP *smp;
88
89         smp = HMAP + vp->ev.e_lno;
90         if (smp > TMAP) {
91                 msgq(sp, M_BERR, "320|Unknown cursor position.");
92                 return (1);
93         }
94         vp->m_stop.lno = smp->lno;
95         vp->m_stop.cno =
96             vs_colpos(sp, smp->lno, vp->ev.e_cno + (smp->soff - 1) * sp->cols);
97         return (mark(sp, vp, 0, BQMARK));
98 }
99
100 /*
101  * mark --
102  *      Mark commands.
103  */
104 static int
105 mark(SCR *sp, VICMD *vp, int getmark, enum which cmd)
106 {
107         dir_t dir;
108         MARK m;
109         size_t len;
110
111         if (getmark && mark_get(sp, vp->character, &vp->m_stop, M_BERR))
112                 return (1);
113
114         /*
115          * !!!
116          * Historically, BQMARKS for character positions that no longer
117          * existed acted as FQMARKS.
118          *
119          * FQMARKS move to the first non-blank.
120          */
121         switch (cmd) {
122         case BQMARK:
123                 if (db_get(sp, vp->m_stop.lno, DBG_FATAL, NULL, &len))
124                         return (1);
125                 if (vp->m_stop.cno < len ||
126                     (vp->m_stop.cno == len && len == 0))
127                         break;
128
129                 if (ISMOTION(vp))
130                         F_SET(vp, VM_LMODE);
131                 cmd = FQMARK;
132                 /* FALLTHROUGH */
133         case FQMARK:
134                 vp->m_stop.cno = 0;
135                 if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno))
136                         return (1);
137                 break;
138         default:
139                 abort();
140         }
141
142         /* Non-motion commands move to the end of the range. */
143         if (!ISMOTION(vp)) {
144                 vp->m_final = vp->m_stop;
145                 return (0);
146         }
147
148         /*
149          * !!!
150          * If a motion component to a BQMARK, the cursor has to move.
151          */
152         if (cmd == BQMARK &&
153             vp->m_stop.lno == vp->m_start.lno &&
154             vp->m_stop.cno == vp->m_start.cno) {
155                 v_nomove(sp);
156                 return (1);
157         }
158
159         /*
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.
165          */
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)) {
169                 m = vp->m_start;
170                 vp->m_start = vp->m_stop;
171                 vp->m_stop = m;
172                 dir = BACKWARD;
173         } else
174                 dir = FORWARD;
175
176         /*
177          * Yank cursor motion, when associated with marks as motion commands,
178          * historically behaved as follows:
179          *
180          * ` motion                     ' motion
181          *              Line change?            Line change?
182          *              Y       N               Y       N
183          *            --------------          ---------------
184          * FORWARD:  |  NM      NM            | NM      NM
185          *           |                        |
186          * BACKWARD: |  M       M             | M       NM(1)
187          *
188          * where NM means the cursor didn't move, and M means the cursor
189          * moved to the mark.
190          *
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.
195          *
196          * Delete cursor motion was always to the start of the text region,
197          * regardless.  Ignore other motion commands.
198          */
199 #ifdef HISTORICAL_PRACTICE
200         if (ISCMD(vp->rkp, 'y')) {
201                 if ((cmd == BQMARK ||
202                     (cmd == FQMARK && vp->m_start.lno != vp->m_stop.lno)) &&
203                     (vp->m_start.lno > vp->m_stop.lno ||
204                     (vp->m_start.lno == vp->m_stop.lno &&
205                     vp->m_start.cno > vp->m_stop.cno)))
206                         vp->m_final = vp->m_stop;
207         } else if (ISCMD(vp->rkp, 'd'))
208                 if (vp->m_start.lno > vp->m_stop.lno ||
209                     (vp->m_start.lno == vp->m_stop.lno &&
210                     vp->m_start.cno > vp->m_stop.cno))
211                         vp->m_final = vp->m_stop;
212 #else
213         vp->m_final = vp->m_start;
214 #endif
215
216         /*
217          * Forward marks are always line oriented, and it's set in the
218          * vcmd.c table.
219          */
220         if (cmd == FQMARK)
221                 return (0);
222
223         /*
224          * BQMARK'S moving backward and starting at column 0, and ones moving
225          * forward and ending at column 0 are corrected to the last column of
226          * the previous line.  Otherwise, adjust the starting/ending point to
227          * the character before the current one (this is safe because we know
228          * the search had to move to succeed).
229          *
230          * Mark motions become line mode opertions if they start at the first
231          * nonblank and end at column 0 of another line.
232          */
233         if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) {
234                 if (db_get(sp, --vp->m_stop.lno, DBG_FATAL, NULL, &len))
235                         return (1);
236                 vp->m_stop.cno = len ? len - 1 : 0;
237                 len = 0;
238                 if (nonblank(sp, vp->m_start.lno, &len))
239                         return (1);
240                 if (vp->m_start.cno <= len)
241                         F_SET(vp, VM_LMODE);
242         } else
243                 --vp->m_stop.cno;
244
245         return (0);
246 }