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