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