]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/nvi/vi/v_left.c
zfs: merge OpenZFS master-891568c99
[FreeBSD/FreeBSD.git] / contrib / nvi / vi / v_left.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 #include <sys/types.h>
13 #include <sys/queue.h>
14 #include <sys/time.h>
15
16 #include <bitstring.h>
17 #include <limits.h>
18 #include <stdio.h>
19
20 #include "../common/common.h"
21 #include "vi.h"
22
23 /*
24  * v_left -- [count]^H, [count]h
25  *      Move left by columns.
26  *
27  * PUBLIC: int v_left(SCR *, VICMD *);
28  */
29 int
30 v_left(SCR *sp, VICMD *vp)
31 {
32         recno_t cnt;
33
34         /*
35          * !!!
36          * The ^H and h commands always failed in the first column.
37          */
38         if (vp->m_start.cno == 0) {
39                 v_sol(sp);
40                 return (1);
41         }
42
43         /* Find the end of the range. */
44         cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
45         if (vp->m_start.cno > cnt)
46                 vp->m_stop.cno = vp->m_start.cno - cnt;
47         else
48                 vp->m_stop.cno = 0;
49
50         /*
51          * All commands move to the end of the range.  Motion commands
52          * adjust the starting point to the character before the current
53          * one.
54          */
55         if (ISMOTION(vp))
56                 --vp->m_start.cno;
57         vp->m_final = vp->m_stop;
58         return (0);
59 }
60
61 /*
62  * v_cfirst -- [count]_
63  *      Move to the first non-blank character in a line.
64  *
65  * PUBLIC: int v_cfirst(SCR *, VICMD *);
66  */
67 int
68 v_cfirst(SCR *sp, VICMD *vp)
69 {
70         recno_t cnt, lno;
71
72         /*
73          * !!!
74          * If the _ is a motion component, it makes the command a line motion
75          * e.g. "d_" deletes the line.  It also means that the cursor doesn't
76          * move.
77          *
78          * The _ command never failed in the first column.
79          */
80         if (ISMOTION(vp))
81                 F_SET(vp, VM_LMODE);
82         /*
83          * !!!
84          * Historically a specified count makes _ move down count - 1
85          * rows, so, "3_" is the same as "2j_".
86          */
87         cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
88         if (cnt != 1) {
89                 --vp->count;
90                 return (v_down(sp, vp));
91         }
92
93         /*
94          * Move to the first non-blank.
95          *
96          * Can't just use RCM_SET_FNB, in case _ is used as the motion
97          * component of another command.
98          */
99         vp->m_stop.cno = 0;
100         if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno))
101                 return (1);
102
103         /*
104          * !!!
105          * The _ command has to fail if the file is empty and we're doing
106          * a delete.  If deleting line 1, and 0 is the first nonblank,
107          * make the check.
108          */
109         if (vp->m_stop.lno == 1 &&
110             vp->m_stop.cno == 0 && ISCMD(vp->rkp, 'd')) {
111                 if (db_last(sp, &lno))
112                         return (1);
113                 if (lno == 0) {
114                         v_sol(sp);
115                         return (1);
116                 }
117         }
118
119         /*
120          * Delete and non-motion commands move to the end of the range,
121          * yank stays at the start.  Ignore others.
122          */
123         vp->m_final =
124             ISMOTION(vp) && ISCMD(vp->rkp, 'y') ? vp->m_start : vp->m_stop;
125         return (0);
126 }
127
128 /*
129  * v_first -- ^
130  *      Move to the first non-blank character in this line.
131  *
132  * PUBLIC: int v_first(SCR *, VICMD *);
133  */
134 int
135 v_first(SCR *sp, VICMD *vp)
136 {
137         /*
138          * !!!
139          * Yielding to none in our quest for compatibility with every
140          * historical blemish of vi, no matter how strange it might be,
141          * we permit the user to enter a count and then ignore it.
142          */
143
144         /*
145          * Move to the first non-blank.
146          *
147          * Can't just use RCM_SET_FNB, in case ^ is used as the motion
148          * component of another command.
149          */
150         vp->m_stop.cno = 0;
151         if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno))
152                 return (1);
153
154         /*
155          * !!!
156          * The ^ command succeeded if used as a command when the cursor was
157          * on the first non-blank in the line, but failed if used as a motion
158          * component in the same situation.
159          */
160         if (ISMOTION(vp) && vp->m_start.cno == vp->m_stop.cno) {
161                 v_sol(sp);
162                 return (1);
163         }
164
165         /*
166          * If moving right, non-motion commands move to the end of the range.
167          * Delete and yank stay at the start.  Motion commands adjust the
168          * ending point to the character before the current ending charcter.
169          *
170          * If moving left, all commands move to the end of the range.  Motion
171          * commands adjust the starting point to the character before the
172          * current starting character.
173          */
174         if (vp->m_start.cno < vp->m_stop.cno)
175                 if (ISMOTION(vp)) {
176                         --vp->m_stop.cno;
177                         vp->m_final = vp->m_start;
178                 } else
179                         vp->m_final = vp->m_stop;
180         else {
181                 if (ISMOTION(vp))
182                         --vp->m_start.cno;
183                 vp->m_final = vp->m_stop;
184         }
185         return (0);
186 }
187
188 /*
189  * v_ncol -- [count]|
190  *      Move to column count or the first column on this line.  If the
191  *      requested column is past EOL, move to EOL.  The nasty part is
192  *      that we have to know character column widths to make this work.
193  *
194  * PUBLIC: int v_ncol(SCR *, VICMD *);
195  */
196 int
197 v_ncol(SCR *sp, VICMD *vp)
198 {
199         if (F_ISSET(vp, VC_C1SET) && vp->count > 1) {
200                 --vp->count;
201                 vp->m_stop.cno =
202                     vs_colpos(sp, vp->m_start.lno, (size_t)vp->count);
203                 /*
204                  * !!!
205                  * The | command succeeded if used as a command and the cursor
206                  * didn't move, but failed if used as a motion component in the
207                  * same situation.
208                  */
209                 if (ISMOTION(vp) && vp->m_stop.cno == vp->m_start.cno) {
210                         v_nomove(sp);
211                         return (1);
212                 }
213         } else {
214                 /*
215                  * !!!
216                  * The | command succeeded if used as a command in column 0
217                  * without a count, but failed if used as a motion component
218                  * in the same situation.
219                  */
220                 if (ISMOTION(vp) && vp->m_start.cno == 0) {
221                         v_sol(sp);
222                         return (1);
223                 }
224                 vp->m_stop.cno = 0;
225         }
226
227         /*
228          * If moving right, non-motion commands move to the end of the range.
229          * Delete and yank stay at the start.  Motion commands adjust the
230          * ending point to the character before the current ending charcter.
231          *
232          * If moving left, all commands move to the end of the range.  Motion
233          * commands adjust the starting point to the character before the
234          * current starting character.
235          */
236         if (vp->m_start.cno < vp->m_stop.cno)
237                 if (ISMOTION(vp)) {
238                         --vp->m_stop.cno;
239                         vp->m_final = vp->m_start;
240                 } else
241                         vp->m_final = vp->m_stop;
242         else {
243                 if (ISMOTION(vp))
244                         --vp->m_start.cno;
245                 vp->m_final = vp->m_stop;
246         }
247         return (0);
248 }
249
250 /*
251  * v_zero -- 0
252  *      Move to the first column on this line.
253  *
254  * PUBLIC: int v_zero(SCR *, VICMD *);
255  */
256 int
257 v_zero(SCR *sp, VICMD *vp)
258 {
259         /*
260          * !!!
261          * The 0 command succeeded if used as a command in the first column
262          * but failed if used as a motion component in the same situation.
263          */
264         if (ISMOTION(vp) && vp->m_start.cno == 0) {
265                 v_sol(sp);
266                 return (1);
267         }
268
269         /*
270          * All commands move to the end of the range.  Motion commands
271          * adjust the starting point to the character before the current
272          * one.
273          */
274         vp->m_stop.cno = 0;
275         if (ISMOTION(vp))
276                 --vp->m_start.cno;
277         vp->m_final = vp->m_stop;
278         return (0);
279 }