]> pd.if.org Git - pd_readline/blob - mg/basic.c
Added mg from an OpenBSD mirror site. Many thanks to the OpenBSD team and the mg...
[pd_readline] / mg / basic.c
1 /*      $OpenBSD: basic.c,v 1.37 2012/06/18 09:26:03 lum Exp $  */
2
3 /* This file is in the public domain */
4
5 /*
6  *              Basic cursor motion commands.
7  *
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.
13  */
14 #include "def.h"
15
16 #include <ctype.h>
17
18 /*
19  * Go to beginning of line.
20  */
21 /* ARGSUSED */
22 int
23 gotobol(int f, int n)
24 {
25         curwp->w_doto = 0;
26         return (TRUE);
27 }
28
29 /*
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.
34  */
35 /* ARGSUSED */
36 int
37 backchar(int f, int n)
38 {
39         struct line   *lp;
40
41         if (n < 0)
42                 return (forwchar(f, -n));
43         while (n--) {
44                 if (curwp->w_doto == 0) {
45                         if ((lp = lback(curwp->w_dotp)) == curbp->b_headp) {
46                                 if (!(f & FFRAND))
47                                         ewprintf("Beginning of buffer");
48                                 return (FALSE);
49                         }
50                         curwp->w_dotp = lp;
51                         curwp->w_doto = llength(lp);
52                         curwp->w_rflag |= WFMOVE;
53                         curwp->w_dotline--;
54                 } else
55                         curwp->w_doto--;
56         }
57         return (TRUE);
58 }
59
60 /*
61  * Go to end of line.
62  */
63 /* ARGSUSED */
64 int
65 gotoeol(int f, int n)
66 {
67         curwp->w_doto = llength(curwp->w_dotp);
68         return (TRUE);
69 }
70
71 /*
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.
76  */
77 /* ARGSUSED */
78 int
79 forwchar(int f, int n)
80 {
81         if (n < 0)
82                 return (backchar(f, -n));
83         while (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);
88                                 if (!(f & FFRAND))
89                                         ewprintf("End of buffer");
90                                 return (FALSE);
91                         }
92                         curwp->w_doto = 0;
93                         curwp->w_dotline++;
94                         curwp->w_rflag |= WFMOVE;
95                 } else
96                         curwp->w_doto++;
97         }
98         return (TRUE);
99 }
100
101 /*
102  * Go to the beginning of the
103  * buffer. Setting WFFULL is conservative,
104  * but almost always the case.
105  */
106 int
107 gotobob(int f, int n)
108 {
109         (void) setmark(f, n);
110         curwp->w_dotp = bfirstlp(curbp);
111         curwp->w_doto = 0;
112         curwp->w_rflag |= WFFULL;
113         curwp->w_dotline = 1;
114         return (TRUE);
115 }
116
117 /*
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.
121  */
122 int
123 gotoeob(int f, int n)
124 {
125         struct line     *lp;
126         
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;
131
132         lp = curwp->w_dotp;
133         n = curwp->w_ntrows - 3;
134
135         if (n < curwp->w_bufp->b_lines && n >= 3) {
136                 while (n--)
137                         curwp->w_dotp = lback(curwp->w_dotp);
138
139                 curwp->w_linep = curwp->w_dotp;
140                 curwp->w_dotp = lp;
141         }
142         curwp->w_rflag |= WFFULL;
143         return (TRUE);
144 }
145
146 /*
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.
152  */
153 /* ARGSUSED */
154 int
155 forwline(int f, int n)
156 {
157         struct line  *dlp;
158
159         if (n < 0)
160                 return (backline(f | FFRAND, -n));
161         if ((dlp = curwp->w_dotp) == curbp->b_headp)
162                 return(TRUE);
163         if ((lastflag & CFCPCN) == 0)   /* Fix goal. */
164                 setgoal();
165         thisflag |= CFCPCN;
166         if (n == 0)
167                 return (TRUE);
168         while (n--) {
169                 dlp = lforw(dlp);
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;
174                         return (TRUE);
175                 }
176                 curwp->w_dotline++;
177         }
178         curwp->w_rflag |= WFMOVE;
179         curwp->w_dotp = dlp;
180         curwp->w_doto = getgoal(dlp);
181
182         return (TRUE);
183 }
184
185 /*
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.
191  */
192 /* ARGSUSED */
193 int
194 backline(int f, int n)
195 {
196         struct line   *dlp;
197
198         if (n < 0)
199                 return (forwline(f | FFRAND, -n));
200         if ((lastflag & CFCPCN) == 0)   /* Fix goal. */
201                 setgoal();
202         thisflag |= CFCPCN;
203         dlp = curwp->w_dotp;
204         while (n-- && lback(dlp) != curbp->b_headp) {
205                 dlp = lback(dlp);
206                 curwp->w_dotline--;
207         }
208         curwp->w_dotp = dlp;
209         curwp->w_doto = getgoal(dlp);
210         curwp->w_rflag |= WFMOVE;
211         return (TRUE);
212 }
213
214 /*
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.
218  */
219 void
220 setgoal(void)
221 {
222         curgoal = getcolpos();          /* Get the position. */
223         /* we can now display past end of display, don't chop! */
224 }
225
226 /*
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.
232  */
233 int
234 getgoal(struct line *dlp)
235 {
236         int c, i, col = 0;
237         char tmp[5];
238
239
240         for (i = 0; i < llength(dlp); i++) {
241                 c = lgetc(dlp, i);
242                 if (c == '\t'
243 #ifdef  NOTAB
244                     && !(curbp->b_flag & BFNOTAB)
245 #endif
246                         ) {
247                         col |= 0x07;
248                         col++;
249                 } else if (ISCTRL(c) != FALSE) {
250                         col += 2;
251                 } else if (isprint(c))
252                         col++;
253                 else {
254                         col += snprintf(tmp, sizeof(tmp), "\\%o", c);
255                 }
256                 if (col > curgoal)
257                         break;
258         }
259         return (i);
260 }
261
262 /*
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.
269  */
270 /* ARGSUSED */
271 int
272 forwpage(int f, int n)
273 {
274         struct line  *lp;
275
276         if (!(f & FFARG)) {
277                 n = curwp->w_ntrows - 2;        /* Default scroll.       */
278                 if (n <= 0)                     /* Forget the overlap    */
279                         n = 1;                  /* if tiny window.       */
280         } else if (n < 0)
281                 return (backpage(f | FFRAND, -n));
282
283         lp = curwp->w_linep;
284         while (n--)
285                 if ((lp = lforw(lp)) == curbp->b_headp) {
286                         ttbeep();
287                         ewprintf("End of buffer");
288                         return(TRUE);
289                 }
290
291         curwp->w_linep = lp;
292         curwp->w_rflag |= WFFULL;
293
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)
297                         return (TRUE);
298
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);
302                 curwp->w_dotline++;
303         }
304         curwp->w_doto = 0;
305         return (TRUE);
306 }
307
308 /*
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.
315  */
316 /* ARGSUSED */
317 int
318 backpage(int f, int n)
319 {
320         struct line  *lp, *lp2;
321
322         if (!(f & FFARG)) {
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.       */
326         } else if (n < 0)
327                 return (forwpage(f | FFRAND, -n));
328
329         lp = lp2 = curwp->w_linep;
330
331         while (n-- && lback(lp) != curbp->b_headp) {
332                 lp = lback(lp);
333         }
334         if (lp == curwp->w_linep) {
335                 ttbeep();
336                 ewprintf("Beginning of buffer");
337         }
338         curwp->w_linep = lp;
339         curwp->w_rflag |= WFFULL;
340
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)
344                         return (TRUE);
345
346         lp2 = lforw(lp2);
347
348         /* Move the dot the slow way, for line nos */
349         while (curwp->w_dotp != lp2) {
350                 if (curwp->w_dotline <= curwp->w_ntrows)
351                         return (TRUE);
352                 curwp->w_dotp = lback(curwp->w_dotp);
353                 curwp->w_dotline--;
354         }
355         curwp->w_doto = 0;
356         return (TRUE);
357 }
358
359 /*
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.
362  */
363 int
364 forw1page(int f, int n)
365 {
366         if (!(f & FFARG)) {
367                 n = 1;
368                 f = FFUNIV;
369         }
370         forwpage(f | FFRAND, n);
371         return (TRUE);
372 }
373
374 int
375 back1page(int f, int n)
376 {
377         if (!(f & FFARG)) {
378                 n = 1;
379                 f = FFUNIV;
380         }
381         backpage(f | FFRAND, n);
382         return (TRUE);
383 }
384
385 /*
386  * Page the other window. Check to make sure it exists, then
387  * nextwind, forwpage and restore window pointers.
388  */
389 int
390 pagenext(int f, int n)
391 {
392         struct mgwin *wp;
393
394         if (wheadp->w_wndp == NULL) {
395                 ewprintf("No other window");
396                 return (FALSE);
397         }
398         wp = curwp;
399         (void) nextwind(f, n);
400         (void) forwpage(f, n);
401         curwp = wp;
402         curbp = wp->w_bufp;
403         return (TRUE);
404 }
405
406 /*
407  * Internal set mark routine, used by other functions (daveb).
408  */
409 void
410 isetmark(void)
411 {
412         curwp->w_markp = curwp->w_dotp;
413         curwp->w_marko = curwp->w_doto;
414         curwp->w_markline = curwp->w_dotline;
415 }
416
417 /*
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)
421  */
422 /* ARGSUSED */
423 int
424 setmark(int f, int n)
425 {
426         isetmark();
427         ewprintf("Mark set");
428         return (TRUE);
429 }
430
431 /* Clear the mark, if set. */
432 /* ARGSUSED */
433 int
434 clearmark(int f, int n)
435 {
436         if (!curwp->w_markp)
437                 return (FALSE);
438
439         curwp->w_markp = NULL;
440         curwp->w_marko = 0;
441         curwp->w_markline = 0;
442
443         return (TRUE);
444 }
445
446 /*
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".
452  */
453 /* ARGSUSED */
454 int
455 swapmark(int f, int n)
456 {
457         struct line  *odotp;
458         int odoto, odotline;
459
460         if (curwp->w_markp == NULL) {
461                 ewprintf("No mark in this window");
462                 return (FALSE);
463         }
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;
474         return (TRUE);
475 }
476
477 /*
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
482  * to use.
483  */
484 /* ARGSUSED */
485 int
486 gotoline(int f, int n)
487 {
488         struct line  *clp;
489         char   buf[32], *bufp;
490         const char *err;
491
492         if (!(f & FFARG)) {
493                 if ((bufp = eread("Goto line: ", buf, sizeof(buf),
494                     EFNUL | EFNEW | EFCR)) == NULL)
495                         return (ABORT);
496                 if (bufp[0] == '\0')
497                         return (ABORT);
498                 n = (int)strtonum(buf, INT_MIN, INT_MAX, &err);
499                 if (err) {
500                         ewprintf("Line number %s", err);
501                         return (FALSE);
502                 }
503         }
504         if (n >= 0) {
505                 if (n == 0)
506                         n++;
507                 curwp->w_dotline = n;
508                 clp = lforw(curbp->b_headp);    /* "clp" is first line */
509                 while (--n > 0) {
510                         if (lforw(clp) == curbp->b_headp) {
511                                 curwp->w_dotline = curwp->w_bufp->b_lines;
512                                 break;
513                         }
514                         clp = lforw(clp);
515                 }
516         } else {
517                 curwp->w_dotline = curwp->w_bufp->b_lines + n;
518                 clp = lback(curbp->b_headp);    /* "clp" is last line */
519                 while (n < 0) {
520                         if (lback(clp) == curbp->b_headp) {
521                                 curwp->w_dotline = 1;
522                                 break;
523                         }
524                         clp = lback(clp);
525                         n++;
526                 }
527         }
528         curwp->w_dotp = clp;
529         curwp->w_doto = 0;
530         curwp->w_rflag |= WFMOVE;
531         return (TRUE);
532 }