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