/* * v_left -- [count]^H, [count]h * Move left by columns. * * PUBLIC: int v_left __P((SCR *, VICMD *)); */ int v_left(SCR *sp, VICMD *vp) { db_recno_t cnt; /* * !!! * The ^H and h commands always failed in the first column. */ if (vp->m_start.cno == 0) { v_sol(sp); return (1); } /* Find the end of the range. */ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; if (vp->m_start.cno > cnt) vp->m_stop.cno = vp->m_start.cno - cnt; else vp->m_stop.cno = 0; /* * All commands move to the end of the range. Motion commands * adjust the starting point to the character before the current * one. */ if (ISMOTION(vp)) --vp->m_start.cno; vp->m_final = vp->m_stop; return (0); }
/* * v_cfirst -- [count]_ * Move to the first non-blank character in a line. * * PUBLIC: int v_cfirst __P((SCR *, VICMD *)); */ int v_cfirst(SCR *sp, VICMD *vp) { db_recno_t cnt, lno; /* * !!! * If the _ is a motion component, it makes the command a line motion * e.g. "d_" deletes the line. It also means that the cursor doesn't * move. * * The _ command never failed in the first column. */ if (ISMOTION(vp)) F_SET(vp, VM_LMODE); /* * !!! * Historically a specified count makes _ move down count - 1 * rows, so, "3_" is the same as "2j_". */ cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; if (cnt != 1) { --vp->count; return (v_down(sp, vp)); } /* * Move to the first non-blank. * * Can't just use RCM_SET_FNB, in case _ is used as the motion * component of another command. */ vp->m_stop.cno = 0; if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno)) return (1); /* * !!! * The _ command has to fail if the file is empty and we're doing * a delete. If deleting line 1, and 0 is the first nonblank, * make the check. */ if (vp->m_stop.lno == 1 && vp->m_stop.cno == 0 && ISCMD(vp->rkp, 'd')) { if (db_last(sp, &lno)) return (1); if (lno == 0) { v_sol(sp); return (1); } } /* * Delete and non-motion commands move to the end of the range, * yank stays at the start. Ignore others. */ vp->m_final = ISMOTION(vp) && ISCMD(vp->rkp, 'y') ? vp->m_start : vp->m_stop; return (0); }
/* * v_ncol -- [count]| * Move to column count or the first column on this line. If the * requested column is past EOL, move to EOL. The nasty part is * that we have to know character column widths to make this work. * * PUBLIC: int v_ncol __P((SCR *, VICMD *)); */ int v_ncol(SCR *sp, VICMD *vp) { if (F_ISSET(vp, VC_C1SET) && vp->count > 1) { --vp->count; vp->m_stop.cno = vs_colpos(sp, vp->m_start.lno, (size_t)vp->count); /* * !!! * The | command succeeded if used as a command and the cursor * didn't move, but failed if used as a motion component in the * same situation. */ if (ISMOTION(vp) && vp->m_stop.cno == vp->m_start.cno) { v_nomove(sp); return (1); } } else { /* * !!! * The | command succeeded if used as a command in column 0 * without a count, but failed if used as a motion component * in the same situation. */ if (ISMOTION(vp) && vp->m_start.cno == 0) { v_sol(sp); return (1); } vp->m_stop.cno = 0; } /* * If moving right, non-motion commands move to the end of the range. * Delete and yank stay at the start. Motion commands adjust the * ending point to the character before the current ending charcter. * * If moving left, all commands move to the end of the range. Motion * commands adjust the starting point to the character before the * current starting character. */ if (vp->m_start.cno < vp->m_stop.cno) if (ISMOTION(vp)) { --vp->m_stop.cno; vp->m_final = vp->m_start; } else vp->m_final = vp->m_stop; else { if (ISMOTION(vp)) --vp->m_start.cno; vp->m_final = vp->m_stop; } return (0); }
/* * v_first -- ^ * Move to the first non-blank character in this line. * * PUBLIC: int v_first __P((SCR *, VICMD *)); */ int v_first(SCR *sp, VICMD *vp) { /* * !!! * Yielding to none in our quest for compatibility with every * historical blemish of vi, no matter how strange it might be, * we permit the user to enter a count and then ignore it. */ /* * Move to the first non-blank. * * Can't just use RCM_SET_FNB, in case ^ is used as the motion * component of another command. */ vp->m_stop.cno = 0; if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno)) return (1); /* * !!! * The ^ command succeeded if used as a command when the cursor was * on the first non-blank in the line, but failed if used as a motion * component in the same situation. */ if (ISMOTION(vp) && vp->m_start.cno == vp->m_stop.cno) { v_sol(sp); return (1); } /* * If moving right, non-motion commands move to the end of the range. * Delete and yank stay at the start. Motion commands adjust the * ending point to the character before the current ending charcter. * * If moving left, all commands move to the end of the range. Motion * commands adjust the starting point to the character before the * current starting character. */ if (vp->m_start.cno < vp->m_stop.cno) if (ISMOTION(vp)) { --vp->m_stop.cno; vp->m_final = vp->m_start; } else vp->m_final = vp->m_stop; else { if (ISMOTION(vp)) --vp->m_start.cno; vp->m_final = vp->m_stop; } return (0); }
/* * Compute the earliest time and position of the intersection of a * sphere and a vertex. * * The sphere has radius R and moves along vector V from point P. The * vertex moves along vector W from point Q in a coordinate system * based at O. */ static float v_vert(float Q[3], const float o[3], const float q[3], const float w[3], const float p[3], const float v[3], float r) { float O[3], P[3], V[3]; float t = LARGE; v_add(O, o, q); v_sub(P, p, O); v_sub(V, v, w); if (v_dot(P, V) < 0.0f) { t = v_sol(P, V, r); if (t < LARGE) v_mad(Q, O, w, t); } return t; }
/* * v_zero -- 0 * Move to the first column on this line. * * PUBLIC: int v_zero __P((SCR *, VICMD *)); */ int v_zero(SCR *sp, VICMD *vp) { /* * !!! * The 0 command succeeded if used as a command in the first column * but failed if used as a motion component in the same situation. */ if (ISMOTION(vp) && vp->m_start.cno == 0) { v_sol(sp); return (1); } /* * All commands move to the end of the range. Motion commands * adjust the starting point to the character before the current * one. */ vp->m_stop.cno = 0; if (ISMOTION(vp)) --vp->m_start.cno; vp->m_final = vp->m_stop; return (0); }
/* * Compute the earliest time and position of the intersection of a * sphere and an edge. * * The sphere has radius R and moves along vector V from point P. The * edge moves along vector W from point Q in a coordinate system based * at O. The edge extends along the length of vector U. */ static float v_edge(float Q[3], const float o[3], const float q[3], const float u[3], const float w[3], const float p[3], const float v[3], float r) { float d[3], e[3]; float P[3], V[3]; float du, eu, uu, s, t; v_sub(d, p, o); v_sub(d, d, q); v_sub(e, v, w); /* * Think projections. Vectors D, extending from the edge vertex Q * to the sphere, and E, the relative velocity of sphere wrt the * edge, are made orthogonal to the edge vector U. Division of * the dot products is required to obtain the true projection * ratios since U does not have unit length. */ du = v_dot(d, u); eu = v_dot(e, u); uu = v_dot(u, u); v_mad(P, d, u, -du / uu); /* First, test for intersection. */ if (v_dot(P, P) < r * r) { /* The sphere already intersects the line of the edge. */ if (du < 0 || du > uu) { /* * The sphere is behind the endpoints of the edge, and * can't hit the edge without hitting the vertices first. */ return LARGE; } /* The sphere already intersects the edge. */ if (v_dot(P, e) >= 0) { /* Moving apart. */ return LARGE; } v_nrm(P, P); v_mad(Q, p, P, -r); return 0; } v_mad(V, e, u, -eu / uu); t = v_sol(P, V, r); s = (du + eu * t) / uu; /* Projection of D + E * t on U. */ if (0.0f <= t && t < LARGE && 0.0f < s && s < 1.0f) { v_mad(d, o, w, t); v_mad(e, q, u, s); v_add(Q, e, d); } else t = LARGE; return t; }