119304Speter/*- 219304Speter * Copyright (c) 1992, 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: v_left.c,v 10.9 2001/06/25 15:19:32 skimo Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 1619304Speter#include <sys/types.h> 1719304Speter#include <sys/queue.h> 1819304Speter#include <sys/time.h> 1919304Speter 2019304Speter#include <bitstring.h> 2119304Speter#include <limits.h> 2219304Speter#include <stdio.h> 2319304Speter 2419304Speter#include "../common/common.h" 2519304Speter#include "vi.h" 2619304Speter 2719304Speter/* 2819304Speter * v_left -- [count]^H, [count]h 2919304Speter * Move left by columns. 3019304Speter * 3119304Speter * PUBLIC: int v_left __P((SCR *, VICMD *)); 3219304Speter */ 3319304Speterint 34254225Speterv_left(SCR *sp, VICMD *vp) 3519304Speter{ 3619304Speter recno_t cnt; 3719304Speter 3819304Speter /* 3919304Speter * !!! 4019304Speter * The ^H and h commands always failed in the first column. 4119304Speter */ 4219304Speter if (vp->m_start.cno == 0) { 4319304Speter v_sol(sp); 4419304Speter return (1); 4519304Speter } 4619304Speter 4719304Speter /* Find the end of the range. */ 4819304Speter cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; 4919304Speter if (vp->m_start.cno > cnt) 5019304Speter vp->m_stop.cno = vp->m_start.cno - cnt; 5119304Speter else 5219304Speter vp->m_stop.cno = 0; 5319304Speter 5419304Speter /* 5519304Speter * All commands move to the end of the range. Motion commands 5619304Speter * adjust the starting point to the character before the current 5719304Speter * one. 5819304Speter */ 5919304Speter if (ISMOTION(vp)) 6019304Speter --vp->m_start.cno; 6119304Speter vp->m_final = vp->m_stop; 6219304Speter return (0); 6319304Speter} 6419304Speter 6519304Speter/* 6619304Speter * v_cfirst -- [count]_ 6719304Speter * Move to the first non-blank character in a line. 6819304Speter * 6919304Speter * PUBLIC: int v_cfirst __P((SCR *, VICMD *)); 7019304Speter */ 7119304Speterint 72254225Speterv_cfirst(SCR *sp, VICMD *vp) 7319304Speter{ 7419304Speter recno_t cnt, lno; 7519304Speter 7619304Speter /* 7719304Speter * !!! 7819304Speter * If the _ is a motion component, it makes the command a line motion 7919304Speter * e.g. "d_" deletes the line. It also means that the cursor doesn't 8019304Speter * move. 8119304Speter * 8219304Speter * The _ command never failed in the first column. 8319304Speter */ 8419304Speter if (ISMOTION(vp)) 8519304Speter F_SET(vp, VM_LMODE); 8619304Speter /* 8719304Speter * !!! 8819304Speter * Historically a specified count makes _ move down count - 1 8919304Speter * rows, so, "3_" is the same as "2j_". 9019304Speter */ 9119304Speter cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; 9219304Speter if (cnt != 1) { 9319304Speter --vp->count; 9419304Speter return (v_down(sp, vp)); 9519304Speter } 9619304Speter 9719304Speter /* 9819304Speter * Move to the first non-blank. 9919304Speter * 10019304Speter * Can't just use RCM_SET_FNB, in case _ is used as the motion 10119304Speter * component of another command. 10219304Speter */ 10319304Speter vp->m_stop.cno = 0; 10419304Speter if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno)) 10519304Speter return (1); 10619304Speter 10719304Speter /* 10819304Speter * !!! 10919304Speter * The _ command has to fail if the file is empty and we're doing 11019304Speter * a delete. If deleting line 1, and 0 is the first nonblank, 11119304Speter * make the check. 11219304Speter */ 11319304Speter if (vp->m_stop.lno == 1 && 11419304Speter vp->m_stop.cno == 0 && ISCMD(vp->rkp, 'd')) { 11519304Speter if (db_last(sp, &lno)) 11619304Speter return (1); 11719304Speter if (lno == 0) { 11819304Speter v_sol(sp); 11919304Speter return (1); 12019304Speter } 12119304Speter } 12219304Speter 12319304Speter /* 12419304Speter * Delete and non-motion commands move to the end of the range, 12519304Speter * yank stays at the start. Ignore others. 12619304Speter */ 12719304Speter vp->m_final = 12819304Speter ISMOTION(vp) && ISCMD(vp->rkp, 'y') ? vp->m_start : vp->m_stop; 12919304Speter return (0); 13019304Speter} 13119304Speter 13219304Speter/* 13319304Speter * v_first -- ^ 13419304Speter * Move to the first non-blank character in this line. 13519304Speter * 13619304Speter * PUBLIC: int v_first __P((SCR *, VICMD *)); 13719304Speter */ 13819304Speterint 139254225Speterv_first(SCR *sp, VICMD *vp) 14019304Speter{ 14119304Speter /* 14219304Speter * !!! 14319304Speter * Yielding to none in our quest for compatibility with every 14419304Speter * historical blemish of vi, no matter how strange it might be, 14519304Speter * we permit the user to enter a count and then ignore it. 14619304Speter */ 14719304Speter 14819304Speter /* 14919304Speter * Move to the first non-blank. 15019304Speter * 15119304Speter * Can't just use RCM_SET_FNB, in case ^ is used as the motion 15219304Speter * component of another command. 15319304Speter */ 15419304Speter vp->m_stop.cno = 0; 15519304Speter if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno)) 15619304Speter return (1); 15719304Speter 15819304Speter /* 15919304Speter * !!! 16019304Speter * The ^ command succeeded if used as a command when the cursor was 16119304Speter * on the first non-blank in the line, but failed if used as a motion 16219304Speter * component in the same situation. 16319304Speter */ 16419304Speter if (ISMOTION(vp) && vp->m_start.cno == vp->m_stop.cno) { 16519304Speter v_sol(sp); 16619304Speter return (1); 16719304Speter } 16819304Speter 16919304Speter /* 17019304Speter * If moving right, non-motion commands move to the end of the range. 17119304Speter * Delete and yank stay at the start. Motion commands adjust the 17219304Speter * ending point to the character before the current ending charcter. 17319304Speter * 17419304Speter * If moving left, all commands move to the end of the range. Motion 17519304Speter * commands adjust the starting point to the character before the 17619304Speter * current starting character. 17719304Speter */ 17819304Speter if (vp->m_start.cno < vp->m_stop.cno) 17919304Speter if (ISMOTION(vp)) { 18019304Speter --vp->m_stop.cno; 18119304Speter vp->m_final = vp->m_start; 18219304Speter } else 18319304Speter vp->m_final = vp->m_stop; 18419304Speter else { 18519304Speter if (ISMOTION(vp)) 18619304Speter --vp->m_start.cno; 18719304Speter vp->m_final = vp->m_stop; 18819304Speter } 18919304Speter return (0); 19019304Speter} 19119304Speter 19219304Speter/* 19319304Speter * v_ncol -- [count]| 19419304Speter * Move to column count or the first column on this line. If the 19519304Speter * requested column is past EOL, move to EOL. The nasty part is 19619304Speter * that we have to know character column widths to make this work. 19719304Speter * 19819304Speter * PUBLIC: int v_ncol __P((SCR *, VICMD *)); 19919304Speter */ 20019304Speterint 201254225Speterv_ncol(SCR *sp, VICMD *vp) 20219304Speter{ 20319304Speter if (F_ISSET(vp, VC_C1SET) && vp->count > 1) { 20419304Speter --vp->count; 20519304Speter vp->m_stop.cno = 20619304Speter vs_colpos(sp, vp->m_start.lno, (size_t)vp->count); 20719304Speter /* 20819304Speter * !!! 20919304Speter * The | command succeeded if used as a command and the cursor 21019304Speter * didn't move, but failed if used as a motion component in the 21119304Speter * same situation. 21219304Speter */ 21319304Speter if (ISMOTION(vp) && vp->m_stop.cno == vp->m_start.cno) { 21419304Speter v_nomove(sp); 21519304Speter return (1); 21619304Speter } 21719304Speter } else { 21819304Speter /* 21919304Speter * !!! 22019304Speter * The | command succeeded if used as a command in column 0 22119304Speter * without a count, but failed if used as a motion component 22219304Speter * in the same situation. 22319304Speter */ 22419304Speter if (ISMOTION(vp) && vp->m_start.cno == 0) { 22519304Speter v_sol(sp); 22619304Speter return (1); 22719304Speter } 22819304Speter vp->m_stop.cno = 0; 22919304Speter } 23019304Speter 23119304Speter /* 23219304Speter * If moving right, non-motion commands move to the end of the range. 23319304Speter * Delete and yank stay at the start. Motion commands adjust the 23419304Speter * ending point to the character before the current ending charcter. 23519304Speter * 23619304Speter * If moving left, all commands move to the end of the range. Motion 23719304Speter * commands adjust the starting point to the character before the 23819304Speter * current starting character. 23919304Speter */ 24019304Speter if (vp->m_start.cno < vp->m_stop.cno) 24119304Speter if (ISMOTION(vp)) { 24219304Speter --vp->m_stop.cno; 24319304Speter vp->m_final = vp->m_start; 24419304Speter } else 24519304Speter vp->m_final = vp->m_stop; 24619304Speter else { 24719304Speter if (ISMOTION(vp)) 24819304Speter --vp->m_start.cno; 24919304Speter vp->m_final = vp->m_stop; 25019304Speter } 25119304Speter return (0); 25219304Speter} 25319304Speter 25419304Speter/* 25519304Speter * v_zero -- 0 25619304Speter * Move to the first column on this line. 25719304Speter * 25819304Speter * PUBLIC: int v_zero __P((SCR *, VICMD *)); 25919304Speter */ 26019304Speterint 261254225Speterv_zero(SCR *sp, VICMD *vp) 26219304Speter{ 26319304Speter /* 26419304Speter * !!! 26519304Speter * The 0 command succeeded if used as a command in the first column 26619304Speter * but failed if used as a motion component in the same situation. 26719304Speter */ 26819304Speter if (ISMOTION(vp) && vp->m_start.cno == 0) { 26919304Speter v_sol(sp); 27019304Speter return (1); 27119304Speter } 27219304Speter 27319304Speter /* 27419304Speter * All commands move to the end of the range. Motion commands 27519304Speter * adjust the starting point to the character before the current 27619304Speter * one. 27719304Speter */ 27819304Speter vp->m_stop.cno = 0; 27919304Speter if (ISMOTION(vp)) 28019304Speter --vp->m_start.cno; 28119304Speter vp->m_final = vp->m_stop; 28219304Speter return (0); 28319304Speter} 284