1/* $NetBSD: v_mark.c,v 1.2 2008/12/05 22:51:43 christos Exp $ */ 2 3/*- 4 * Copyright (c) 1992, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * Copyright (c) 1992, 1993, 1994, 1995, 1996 7 * Keith Bostic. All rights reserved. 8 * 9 * See the LICENSE file for redistribution information. 10 */ 11 12#include "config.h" 13 14#ifndef lint 15static const char sccsid[] = "Id: v_mark.c,v 10.12 2001/06/25 15:19:32 skimo Exp (Berkeley) Date: 2001/06/25 15:19:32"; 16#endif /* not lint */ 17 18#include <sys/types.h> 19#include <sys/queue.h> 20#include <sys/time.h> 21 22#include <bitstring.h> 23#include <limits.h> 24#include <stdlib.h> 25#include <stdio.h> 26 27#include "../common/common.h" 28#include "vi.h" 29 30enum which {BQMARK, FQMARK}; 31static int mark __P((SCR *, VICMD *, int, enum which)); 32 33/* 34 * v_mark -- m[a-z] 35 * Set a mark. 36 * 37 * PUBLIC: int v_mark __P((SCR *, VICMD *)); 38 */ 39int 40v_mark(SCR *sp, VICMD *vp) 41{ 42 return (mark_set(sp, vp->character, &vp->m_start, 1)); 43} 44 45/* 46 * v_bmark -- `['`a-z] 47 * Move to a mark. 48 * 49 * Moves to a mark, setting both row and column. 50 * 51 * !!! 52 * Although not commonly known, the "'`" and "'`" forms are historically 53 * valid. The behavior is determined by the first character, so "`'" is 54 * the same as "``". Remember this fact -- you'll be amazed at how many 55 * people don't know it and will be delighted that you are able to tell 56 * them. 57 * 58 * PUBLIC: int v_bmark __P((SCR *, VICMD *)); 59 */ 60int 61v_bmark(SCR *sp, VICMD *vp) 62{ 63 return (mark(sp, vp, 1, BQMARK)); 64} 65 66/* 67 * v_fmark -- '['`a-z] 68 * Move to a mark. 69 * 70 * Move to the first nonblank character of the line containing the mark. 71 * 72 * PUBLIC: int v_fmark __P((SCR *, VICMD *)); 73 */ 74int 75v_fmark(SCR *sp, VICMD *vp) 76{ 77 return (mark(sp, vp, 1, FQMARK)); 78} 79 80/* 81 * v_emark -- <mouse click> 82 * Mouse mark. 83 * 84 * PUBLIC: int v_emark __P((SCR *, VICMD *)); 85 */ 86int 87v_emark(SCR *sp, VICMD *vp) 88{ 89 SMAP *smp; 90 91 smp = HMAP + vp->ev.e_lno; 92 if (smp > TMAP) { 93 msgq(sp, M_BERR, "320|Unknown cursor position."); 94 return (1); 95 } 96 vp->m_stop.lno = smp->lno; 97 vp->m_stop.cno = 98 vs_colpos(sp, smp->lno, vp->ev.e_cno + (smp->soff - 1) * sp->cols); 99 return (mark(sp, vp, 0, BQMARK)); 100} 101 102/* 103 * mark -- 104 * Mark commands. 105 */ 106static int 107mark(SCR *sp, VICMD *vp, int getmark, enum which cmd) 108{ 109 dir_t dir; 110 MARK m; 111 size_t len; 112 113 if (getmark && mark_get(sp, vp->character, &vp->m_stop, M_BERR)) 114 return (1); 115 116 /* 117 * !!! 118 * Historically, BQMARKS for character positions that no longer 119 * existed acted as FQMARKS. 120 * 121 * FQMARKS move to the first non-blank. 122 */ 123 switch (cmd) { 124 case BQMARK: 125 if (db_get(sp, vp->m_stop.lno, DBG_FATAL, NULL, &len)) 126 return (1); 127 if (vp->m_stop.cno < len || 128 (vp->m_stop.cno == len && len == 0)) 129 break; 130 131 if (ISMOTION(vp)) 132 F_SET(vp, VM_LMODE); 133 cmd = FQMARK; 134 /* FALLTHROUGH */ 135 case FQMARK: 136 vp->m_stop.cno = 0; 137 if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno)) 138 return (1); 139 break; 140 default: 141 abort(); 142 } 143 144 /* Non-motion commands move to the end of the range. */ 145 if (!ISMOTION(vp)) { 146 vp->m_final = vp->m_stop; 147 return (0); 148 } 149 150 /* 151 * !!! 152 * If a motion component to a BQMARK, the cursor has to move. 153 */ 154 if (cmd == BQMARK && 155 vp->m_stop.lno == vp->m_start.lno && 156 vp->m_stop.cno == vp->m_start.cno) { 157 v_nomove(sp); 158 return (1); 159 } 160 161 /* 162 * If the motion is in the reverse direction, switch the start and 163 * stop MARK's so that it's in a forward direction. (There's no 164 * reason for this other than to make the tests below easier. The 165 * code in vi.c:vi() would have done the switch.) Both forward 166 * and backward motions can happen for any kind of search command. 167 */ 168 if (vp->m_start.lno > vp->m_stop.lno || 169 (vp->m_start.lno == vp->m_stop.lno && 170 vp->m_start.cno > vp->m_stop.cno)) { 171 m = vp->m_start; 172 vp->m_start = vp->m_stop; 173 vp->m_stop = m; 174 dir = BACKWARD; 175 } else 176 dir = FORWARD; 177 178 /* 179 * Yank cursor motion, when associated with marks as motion commands, 180 * historically behaved as follows: 181 * 182 * ` motion ' motion 183 * Line change? Line change? 184 * Y N Y N 185 * -------------- --------------- 186 * FORWARD: | NM NM | NM NM 187 * | | 188 * BACKWARD: | M M | M NM(1) 189 * 190 * where NM means the cursor didn't move, and M means the cursor 191 * moved to the mark. 192 * 193 * As the cursor was usually moved for yank commands associated 194 * with backward motions, this implementation regularizes it by 195 * changing the NM at position (1) to be an M. This makes mark 196 * motions match search motions, which is probably A Good Thing. 197 * 198 * Delete cursor motion was always to the start of the text region, 199 * regardless. Ignore other motion commands. 200 */ 201#ifdef HISTORICAL_PRACTICE 202 if (ISCMD(vp->rkp, 'y')) { 203 if ((cmd == BQMARK || 204 cmd == FQMARK && vp->m_start.lno != vp->m_stop.lno) && 205 (vp->m_start.lno > vp->m_stop.lno || 206 vp->m_start.lno == vp->m_stop.lno && 207 vp->m_start.cno > vp->m_stop.cno)) 208 vp->m_final = vp->m_stop; 209 } else if (ISCMD(vp->rkp, 'd')) 210 if (vp->m_start.lno > vp->m_stop.lno || 211 vp->m_start.lno == vp->m_stop.lno && 212 vp->m_start.cno > vp->m_stop.cno) 213 vp->m_final = vp->m_stop; 214#else 215 vp->m_final = vp->m_start; 216#endif 217 218 /* 219 * Forward marks are always line oriented, and it's set in the 220 * vcmd.c table. 221 */ 222 if (cmd == FQMARK) 223 return (0); 224 225 /* 226 * BQMARK'S moving backward and starting at column 0, and ones moving 227 * forward and ending at column 0 are corrected to the last column of 228 * the previous line. Otherwise, adjust the starting/ending point to 229 * the character before the current one (this is safe because we know 230 * the search had to move to succeed). 231 * 232 * Mark motions become line mode opertions if they start at the first 233 * nonblank and end at column 0 of another line. 234 */ 235 if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) { 236 if (db_get(sp, --vp->m_stop.lno, DBG_FATAL, NULL, &len)) 237 return (1); 238 vp->m_stop.cno = len ? len - 1 : 0; 239 len = 0; 240 if (nonblank(sp, vp->m_start.lno, &len)) 241 return (1); 242 if (vp->m_start.cno <= len) 243 F_SET(vp, VM_LMODE); 244 } else 245 --vp->m_stop.cno; 246 247 return (0); 248} 249