1 /* $OpenBSD: basic.c,v 1.37 2012/06/18 09:26:03 lum Exp $ */
3 /* This file is in the public domain */
6 * Basic cursor motion commands.
8 * The routines in this file are the basic
9 * command functions for moving the cursor around on
10 * the screen, setting mark, and swapping dot with
11 * mark. Only moves between lines, which might make the
12 * current buffer framing bad, are hard.
19 * Go to beginning of line.
30 * Move cursor backwards. Do the
31 * right thing if the count is less than
32 * 0. Error if you try to move back from
33 * the beginning of the buffer.
37 backchar(int f, int n)
42 return (forwchar(f, -n));
44 if (curwp->w_doto == 0) {
45 if ((lp = lback(curwp->w_dotp)) == curbp->b_headp) {
47 ewprintf("Beginning of buffer");
51 curwp->w_doto = llength(lp);
52 curwp->w_rflag |= WFMOVE;
67 curwp->w_doto = llength(curwp->w_dotp);
72 * Move cursor forwards. Do the
73 * right thing if the count is less than
74 * 0. Error if you try to move forward
75 * from the end of the buffer.
79 forwchar(int f, int n)
82 return (backchar(f, -n));
84 if (curwp->w_doto == llength(curwp->w_dotp)) {
85 curwp->w_dotp = lforw(curwp->w_dotp);
86 if (curwp->w_dotp == curbp->b_headp) {
87 curwp->w_dotp = lback(curwp->w_dotp);
89 ewprintf("End of buffer");
94 curwp->w_rflag |= WFMOVE;
102 * Go to the beginning of the
103 * buffer. Setting WFFULL is conservative,
104 * but almost always the case.
107 gotobob(int f, int n)
109 (void) setmark(f, n);
110 curwp->w_dotp = bfirstlp(curbp);
112 curwp->w_rflag |= WFFULL;
113 curwp->w_dotline = 1;
118 * Go to the end of the buffer. Leave dot 3 lines from the bottom of the
119 * window if buffer length is longer than window length; same as emacs.
120 * Setting WFFULL is conservative, but almost always the case.
123 gotoeob(int f, int n)
127 (void) setmark(f, n);
128 curwp->w_dotp = blastlp(curbp);
129 curwp->w_doto = llength(curwp->w_dotp);
130 curwp->w_dotline = curwp->w_bufp->b_lines;
133 n = curwp->w_ntrows - 3;
135 if (n < curwp->w_bufp->b_lines && n >= 3) {
137 curwp->w_dotp = lback(curwp->w_dotp);
139 curwp->w_linep = curwp->w_dotp;
142 curwp->w_rflag |= WFFULL;
147 * Move forward by full lines.
148 * If the number of lines to move is less
149 * than zero, call the backward line function to
150 * actually do it. The last command controls how
151 * the goal column is set.
155 forwline(int f, int n)
160 return (backline(f | FFRAND, -n));
161 if ((dlp = curwp->w_dotp) == curbp->b_headp)
163 if ((lastflag & CFCPCN) == 0) /* Fix goal. */
170 if (dlp == curbp->b_headp) {
171 curwp->w_dotp = lback(dlp);
172 curwp->w_doto = llength(curwp->w_dotp);
173 curwp->w_rflag |= WFMOVE;
178 curwp->w_rflag |= WFMOVE;
180 curwp->w_doto = getgoal(dlp);
186 * This function is like "forwline", but
187 * goes backwards. The scheme is exactly the same.
188 * Check for arguments that are less than zero and
189 * call your alternate. Figure out the new line and
190 * call "movedot" to perform the motion.
194 backline(int f, int n)
199 return (forwline(f | FFRAND, -n));
200 if ((lastflag & CFCPCN) == 0) /* Fix goal. */
204 while (n-- && lback(dlp) != curbp->b_headp) {
209 curwp->w_doto = getgoal(dlp);
210 curwp->w_rflag |= WFMOVE;
215 * Set the current goal column, which is saved in the external variable
216 * "curgoal", to the current cursor column. The column is never off
217 * the edge of the screen; it's more like display then show position.
222 curgoal = getcolpos(); /* Get the position. */
223 /* we can now display past end of display, don't chop! */
227 * This routine looks at a line (pointed
228 * to by the LINE pointer "dlp") and the current
229 * vertical motion goal column (set by the "setgoal"
230 * routine above) and returns the best offset to use
231 * when a vertical motion is made into the line.
234 getgoal(struct line *dlp)
240 for (i = 0; i < llength(dlp); i++) {
244 && !(curbp->b_flag & BFNOTAB)
249 } else if (ISCTRL(c) != FALSE) {
251 } else if (isprint(c))
254 col += snprintf(tmp, sizeof(tmp), "\\%o", c);
263 * Scroll forward by a specified number
264 * of lines, or by a full page if no argument.
265 * The "2" is the window overlap (this is the default
266 * value from ITS EMACS). Because the top line in
267 * the window is zapped, we have to do a hard
268 * update and get it back.
272 forwpage(int f, int n)
277 n = curwp->w_ntrows - 2; /* Default scroll. */
278 if (n <= 0) /* Forget the overlap */
279 n = 1; /* if tiny window. */
281 return (backpage(f | FFRAND, -n));
285 if ((lp = lforw(lp)) == curbp->b_headp) {
287 ewprintf("End of buffer");
292 curwp->w_rflag |= WFFULL;
294 /* if in current window, don't move dot */
295 for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp))
296 if (lp == curwp->w_dotp)
299 /* Advance the dot the slow way, for line nos */
300 while (curwp->w_dotp != curwp->w_linep) {
301 curwp->w_dotp = lforw(curwp->w_dotp);
309 * This command is like "forwpage",
310 * but it goes backwards. The "2", like above,
311 * is the overlap between the two windows. The
312 * value is from the ITS EMACS manual. The
313 * hard update is done because the top line in
314 * the window is zapped.
318 backpage(int f, int n)
320 struct line *lp, *lp2;
323 n = curwp->w_ntrows - 2; /* Default scroll. */
324 if (n <= 0) /* Don't blow up if the */
325 return (backline(f, 1));/* window is tiny. */
327 return (forwpage(f | FFRAND, -n));
329 lp = lp2 = curwp->w_linep;
331 while (n-- && lback(lp) != curbp->b_headp) {
334 if (lp == curwp->w_linep) {
336 ewprintf("Beginning of buffer");
339 curwp->w_rflag |= WFFULL;
341 /* if in current window, don't move dot */
342 for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp))
343 if (lp == curwp->w_dotp)
348 /* Move the dot the slow way, for line nos */
349 while (curwp->w_dotp != lp2) {
350 if (curwp->w_dotline <= curwp->w_ntrows)
352 curwp->w_dotp = lback(curwp->w_dotp);
360 * These functions are provided for compatibility with Gosling's Emacs. They
361 * are used to scroll the display up (or down) one line at a time.
364 forw1page(int f, int n)
370 forwpage(f | FFRAND, n);
375 back1page(int f, int n)
381 backpage(f | FFRAND, n);
386 * Page the other window. Check to make sure it exists, then
387 * nextwind, forwpage and restore window pointers.
390 pagenext(int f, int n)
394 if (wheadp->w_wndp == NULL) {
395 ewprintf("No other window");
399 (void) nextwind(f, n);
400 (void) forwpage(f, n);
407 * Internal set mark routine, used by other functions (daveb).
412 curwp->w_markp = curwp->w_dotp;
413 curwp->w_marko = curwp->w_doto;
414 curwp->w_markline = curwp->w_dotline;
418 * Set the mark in the current window
419 * to the value of dot. A message is written to
420 * the echo line. (ewprintf knows about macros)
424 setmark(int f, int n)
427 ewprintf("Mark set");
431 /* Clear the mark, if set. */
434 clearmark(int f, int n)
439 curwp->w_markp = NULL;
441 curwp->w_markline = 0;
447 * Swap the values of "dot" and "mark" in
448 * the current window. This is pretty easy, because
449 * all of the hard work gets done by the standard routine
450 * that moves the mark about. The only possible
451 * error is "no mark".
455 swapmark(int f, int n)
460 if (curwp->w_markp == NULL) {
461 ewprintf("No mark in this window");
464 odotp = curwp->w_dotp;
465 odoto = curwp->w_doto;
466 odotline = curwp->w_dotline;
467 curwp->w_dotp = curwp->w_markp;
468 curwp->w_doto = curwp->w_marko;
469 curwp->w_dotline = curwp->w_markline;
470 curwp->w_markp = odotp;
471 curwp->w_marko = odoto;
472 curwp->w_markline = odotline;
473 curwp->w_rflag |= WFMOVE;
478 * Go to a specific line, mostly for
479 * looking up errors in C programs, which give the
480 * error a line number. If an argument is present, then
481 * it is the line number, else prompt for a line number
486 gotoline(int f, int n)
493 if ((bufp = eread("Goto line: ", buf, sizeof(buf),
494 EFNUL | EFNEW | EFCR)) == NULL)
498 n = (int)strtonum(buf, INT_MIN, INT_MAX, &err);
500 ewprintf("Line number %s", err);
507 curwp->w_dotline = n;
508 clp = lforw(curbp->b_headp); /* "clp" is first line */
510 if (lforw(clp) == curbp->b_headp) {
511 curwp->w_dotline = curwp->w_bufp->b_lines;
517 curwp->w_dotline = curwp->w_bufp->b_lines + n;
518 clp = lback(curbp->b_headp); /* "clp" is last line */
520 if (lback(clp) == curbp->b_headp) {
521 curwp->w_dotline = 1;
530 curwp->w_rflag |= WFMOVE;