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_mark.c,v 10.12 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 <stdlib.h> 2319304Speter#include <stdio.h> 2419304Speter 2519304Speter#include "../common/common.h" 2619304Speter#include "vi.h" 2719304Speter 28254225Speterenum which {BQMARK, FQMARK}; 29281373Sbaptstatic int mark(SCR *, VICMD *, int, enum which); 30254225Speter 3119304Speter/* 3219304Speter * v_mark -- m[a-z] 3319304Speter * Set a mark. 3419304Speter * 35281373Sbapt * PUBLIC: int v_mark(SCR *, VICMD *); 3619304Speter */ 3719304Speterint 38254225Speterv_mark(SCR *sp, VICMD *vp) 3919304Speter{ 4019304Speter return (mark_set(sp, vp->character, &vp->m_start, 1)); 4119304Speter} 4219304Speter 4319304Speter/* 4419304Speter * v_bmark -- `['`a-z] 4519304Speter * Move to a mark. 4619304Speter * 4719304Speter * Moves to a mark, setting both row and column. 4819304Speter * 4919304Speter * !!! 5019304Speter * Although not commonly known, the "'`" and "'`" forms are historically 5119304Speter * valid. The behavior is determined by the first character, so "`'" is 5219304Speter * the same as "``". Remember this fact -- you'll be amazed at how many 5319304Speter * people don't know it and will be delighted that you are able to tell 5419304Speter * them. 5519304Speter * 56281373Sbapt * PUBLIC: int v_bmark(SCR *, VICMD *); 5719304Speter */ 5819304Speterint 59254225Speterv_bmark(SCR *sp, VICMD *vp) 6019304Speter{ 61254225Speter return (mark(sp, vp, 1, BQMARK)); 6219304Speter} 6319304Speter 6419304Speter/* 6519304Speter * v_fmark -- '['`a-z] 6619304Speter * Move to a mark. 6719304Speter * 6819304Speter * Move to the first nonblank character of the line containing the mark. 6919304Speter * 70281373Sbapt * PUBLIC: int v_fmark(SCR *, VICMD *); 7119304Speter */ 7219304Speterint 73254225Speterv_fmark(SCR *sp, VICMD *vp) 7419304Speter{ 75254225Speter return (mark(sp, vp, 1, FQMARK)); 7619304Speter} 7719304Speter 7819304Speter/* 79254225Speter * v_emark -- <mouse click> 80254225Speter * Mouse mark. 81254225Speter * 82281373Sbapt * PUBLIC: int v_emark(SCR *, VICMD *); 83254225Speter */ 84254225Speterint 85254225Speterv_emark(SCR *sp, VICMD *vp) 86254225Speter{ 87254225Speter SMAP *smp; 88254225Speter 89254225Speter smp = HMAP + vp->ev.e_lno; 90254225Speter if (smp > TMAP) { 91254225Speter msgq(sp, M_BERR, "320|Unknown cursor position."); 92254225Speter return (1); 93254225Speter } 94254225Speter vp->m_stop.lno = smp->lno; 95254225Speter vp->m_stop.cno = 96254225Speter vs_colpos(sp, smp->lno, vp->ev.e_cno + (smp->soff - 1) * sp->cols); 97254225Speter return (mark(sp, vp, 0, BQMARK)); 98254225Speter} 99254225Speter 100254225Speter/* 10119304Speter * mark -- 10219304Speter * Mark commands. 10319304Speter */ 10419304Speterstatic int 105254225Spetermark(SCR *sp, VICMD *vp, int getmark, enum which cmd) 10619304Speter{ 10719304Speter dir_t dir; 10819304Speter MARK m; 10919304Speter size_t len; 11019304Speter 111254225Speter if (getmark && mark_get(sp, vp->character, &vp->m_stop, M_BERR)) 11219304Speter return (1); 11319304Speter 11419304Speter /* 11519304Speter * !!! 11619304Speter * Historically, BQMARKS for character positions that no longer 11719304Speter * existed acted as FQMARKS. 11819304Speter * 11919304Speter * FQMARKS move to the first non-blank. 12019304Speter */ 12119304Speter switch (cmd) { 12219304Speter case BQMARK: 12319304Speter if (db_get(sp, vp->m_stop.lno, DBG_FATAL, NULL, &len)) 12419304Speter return (1); 12519304Speter if (vp->m_stop.cno < len || 126254225Speter (vp->m_stop.cno == len && len == 0)) 12719304Speter break; 12819304Speter 12919304Speter if (ISMOTION(vp)) 13019304Speter F_SET(vp, VM_LMODE); 13119304Speter cmd = FQMARK; 13219304Speter /* FALLTHROUGH */ 13319304Speter case FQMARK: 13419304Speter vp->m_stop.cno = 0; 13519304Speter if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno)) 13619304Speter return (1); 13719304Speter break; 13819304Speter default: 13919304Speter abort(); 14019304Speter } 14119304Speter 14219304Speter /* Non-motion commands move to the end of the range. */ 14319304Speter if (!ISMOTION(vp)) { 14419304Speter vp->m_final = vp->m_stop; 14519304Speter return (0); 14619304Speter } 14719304Speter 14819304Speter /* 14919304Speter * !!! 15019304Speter * If a motion component to a BQMARK, the cursor has to move. 15119304Speter */ 15219304Speter if (cmd == BQMARK && 15319304Speter vp->m_stop.lno == vp->m_start.lno && 15419304Speter vp->m_stop.cno == vp->m_start.cno) { 15519304Speter v_nomove(sp); 15619304Speter return (1); 15719304Speter } 15819304Speter 15919304Speter /* 16019304Speter * If the motion is in the reverse direction, switch the start and 16119304Speter * stop MARK's so that it's in a forward direction. (There's no 16219304Speter * reason for this other than to make the tests below easier. The 16319304Speter * code in vi.c:vi() would have done the switch.) Both forward 16419304Speter * and backward motions can happen for any kind of search command. 16519304Speter */ 16619304Speter if (vp->m_start.lno > vp->m_stop.lno || 167254225Speter (vp->m_start.lno == vp->m_stop.lno && 168254225Speter vp->m_start.cno > vp->m_stop.cno)) { 16919304Speter m = vp->m_start; 17019304Speter vp->m_start = vp->m_stop; 17119304Speter vp->m_stop = m; 17219304Speter dir = BACKWARD; 17319304Speter } else 17419304Speter dir = FORWARD; 17519304Speter 17619304Speter /* 17719304Speter * Yank cursor motion, when associated with marks as motion commands, 17819304Speter * historically behaved as follows: 17919304Speter * 18019304Speter * ` motion ' motion 18119304Speter * Line change? Line change? 18219304Speter * Y N Y N 18319304Speter * -------------- --------------- 18419304Speter * FORWARD: | NM NM | NM NM 18519304Speter * | | 18619304Speter * BACKWARD: | M M | M NM(1) 18719304Speter * 18819304Speter * where NM means the cursor didn't move, and M means the cursor 18919304Speter * moved to the mark. 19019304Speter * 19119304Speter * As the cursor was usually moved for yank commands associated 19219304Speter * with backward motions, this implementation regularizes it by 19319304Speter * changing the NM at position (1) to be an M. This makes mark 19419304Speter * motions match search motions, which is probably A Good Thing. 19519304Speter * 19619304Speter * Delete cursor motion was always to the start of the text region, 19719304Speter * regardless. Ignore other motion commands. 19819304Speter */ 19919304Speter vp->m_final = vp->m_start; 20019304Speter 20119304Speter /* 20219304Speter * Forward marks are always line oriented, and it's set in the 20319304Speter * vcmd.c table. 20419304Speter */ 20519304Speter if (cmd == FQMARK) 20619304Speter return (0); 20719304Speter 20819304Speter /* 20919304Speter * BQMARK'S moving backward and starting at column 0, and ones moving 21019304Speter * forward and ending at column 0 are corrected to the last column of 21119304Speter * the previous line. Otherwise, adjust the starting/ending point to 21219304Speter * the character before the current one (this is safe because we know 21319304Speter * the search had to move to succeed). 21419304Speter * 21519304Speter * Mark motions become line mode opertions if they start at the first 21619304Speter * nonblank and end at column 0 of another line. 21719304Speter */ 21819304Speter if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) { 21919304Speter if (db_get(sp, --vp->m_stop.lno, DBG_FATAL, NULL, &len)) 22019304Speter return (1); 22119304Speter vp->m_stop.cno = len ? len - 1 : 0; 22219304Speter len = 0; 22319304Speter if (nonblank(sp, vp->m_start.lno, &len)) 22419304Speter return (1); 22519304Speter if (vp->m_start.cno <= len) 22619304Speter F_SET(vp, VM_LMODE); 22719304Speter } else 22819304Speter --vp->m_stop.cno; 22919304Speter 23019304Speter return (0); 23119304Speter} 232