1 /* @(#)cursorcmds.c 1.35 19/09/05 Copyright 1984-2019 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)cursorcmds.c 1.35 19/09/05 Copyright 1984-2019 J. Schilling";
6 #endif
7 /*
8 * Commands that deal with cursor movement
9 *
10 * Copyright (c) 1984-2019 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include "ved.h"
27 #include "movedot.h"
28 #include "terminal.h"
29
30 EXPORT BOOL dosnl __PR((ewin_t *wp, epos_t pos));
31 EXPORT void vforw __PR((ewin_t *wp));
32 EXPORT void vsforw __PR((ewin_t *wp));
33 EXPORT void vwforw __PR((ewin_t *wp));
34 EXPORT void vswforw __PR((ewin_t *wp));
35 EXPORT void vrev __PR((ewin_t *wp));
36 EXPORT void vsrev __PR((ewin_t *wp));
37 EXPORT void vwrev __PR((ewin_t *wp));
38 EXPORT void vswrev __PR((ewin_t *wp));
39 EXPORT void vup __PR((ewin_t *wp));
40 EXPORT void vsup __PR((ewin_t *wp));
41 EXPORT void vpup __PR((ewin_t *wp));
42 EXPORT void vspup __PR((ewin_t *wp));
43 EXPORT void vdown __PR((ewin_t *wp));
44 EXPORT void vsdown __PR((ewin_t *wp));
45 EXPORT void vpdown __PR((ewin_t *wp));
46 EXPORT void vspdwn __PR((ewin_t *wp));
47 EXPORT void vpageup __PR((ewin_t *wp));
48 EXPORT void vspageup __PR((ewin_t *wp));
49 EXPORT void vpagedwn __PR((ewin_t *wp));
50 EXPORT void vspagedwn __PR((ewin_t *wp));
51 EXPORT void vend __PR((ewin_t *wp));
52 EXPORT void vsend __PR((ewin_t *wp));
53 EXPORT void vpend __PR((ewin_t *wp));
54 EXPORT void vspend __PR((ewin_t *wp));
55 EXPORT void vbegin __PR((ewin_t *wp));
56 EXPORT void vsbegin __PR((ewin_t *wp));
57 EXPORT void vpbegin __PR((ewin_t *wp));
58 EXPORT void vspbegin __PR((ewin_t *wp));
59 EXPORT void vtop __PR((ewin_t *wp));
60 EXPORT void vstop __PR((ewin_t *wp));
61 EXPORT void vbottom __PR((ewin_t *wp));
62 EXPORT void vsbottom __PR((ewin_t *wp));
63 EXPORT void vadjwin __PR((ewin_t *wp));
64 EXPORT void vredisp __PR((ewin_t *wp));
65 EXPORT void vltopwin __PR((ewin_t *wp));
66 LOCAL epos_t srchbrack __PR((ewin_t *wp, epos_t begin, int ch, epos_t (*)(ewin_t *wp, epos_t, Uchar *, int, int)));
67 LOCAL epos_t searchbrack __PR((ewin_t *wp, epos_t begin, int ch));
68 EXPORT void vbrack __PR((ewin_t *wp));
69
70 /*
71 * Check if dot points to a DOS CR-LF combination.
72 * Dot in this case points to the LF character.
73 */
74 EXPORT BOOL
dosnl(wp,pos)75 dosnl(wp, pos)
76 ewin_t *wp;
77 epos_t pos;
78 {
79 Uchar b[2+1]; /* \r\n\0 */
80
81 if (pos <= 0)
82 return (FALSE);
83 if (extract(wp, pos, b, 2) == 2) {
84 if (b[0] == '\r' && b[1] == '\n') {
85 return (TRUE);
86 }
87 }
88 return (FALSE);
89 }
90
91 /*
92 * Move cursor forwards 'curnum' characters
93 */
94 EXPORT void
vforw(wp)95 vforw(wp)
96 ewin_t *wp;
97 {
98 if (wp->dot == wp->eof) {
99 ringbell();
100 } else {
101 if (wp->eof-wp->dot < wp->curnum)
102 wp->dot = wp->eof;
103 else
104 wp->dot += wp->curnum;
105
106 if (wp->dosmode && (wp->eof - wp->dot) >= 1 && dosnl(wp, wp->dot -1))
107 wp->dot += 1;
108 }
109 }
110
111 /*
112 * Set mark, then move cursor forwards 'curnum' characters
113 */
114 EXPORT void
vsforw(wp)115 vsforw(wp)
116 ewin_t *wp;
117 {
118 setmark(wp, wp->dot);
119 vforw(wp);
120 }
121
122 /*
123 * Move cursor forwards 'curnum' words
124 */
125 EXPORT void
vwforw(wp)126 vwforw(wp)
127 ewin_t *wp;
128 {
129 if (wp->dot == wp->eof) {
130 ringbell();
131 } else {
132 wp->dot = forwword(wp, wp->dot, wp->curnum);
133 }
134 }
135
136 /*
137 * Set mark, then move cursor forwards 'curnum' words
138 */
139 EXPORT void
vswforw(wp)140 vswforw(wp)
141 ewin_t *wp;
142 {
143 setmark(wp, wp->dot);
144 vwforw(wp);
145 }
146
147 /*
148 * Move cursor backwards 'curnum' characters
149 */
150 EXPORT void
vrev(wp)151 vrev(wp)
152 ewin_t *wp;
153 {
154 if (wp->dot == 0) {
155 ringbell();
156 } else {
157 if (wp->dot < wp->curnum)
158 wp->dot = 0;
159 else
160 wp->dot -= wp->curnum;
161
162 if (wp->dosmode && wp->dot >= 1 && dosnl(wp, wp->dot -1))
163 wp->dot -= 1;
164 }
165 }
166
167 /*
168 * Set mark, then move cursor backwards 'curnum' characters
169 */
170 EXPORT void
vsrev(wp)171 vsrev(wp)
172 ewin_t *wp;
173 {
174 setmark(wp, wp->dot);
175 vrev(wp);
176 }
177
178 /*
179 * Move cursor backwards 'curnum' words
180 */
181 EXPORT void
vwrev(wp)182 vwrev(wp)
183 ewin_t *wp;
184 {
185 if (wp->dot == 0) {
186 ringbell();
187 } else {
188 /*
189 * Count == 1 moves to the begining of current word.
190 * The rest moves back for 'curnum' words.
191 */
192 wp->dot = revword(wp, wp->dot, wp->curnum);
193 }
194 }
195
196 /*
197 * Set mark, then move cursor backwards 'curnum' words
198 */
199 EXPORT void
vswrev(wp)200 vswrev(wp)
201 ewin_t *wp;
202 {
203 setmark(wp, wp->dot);
204 vwrev(wp);
205 }
206
207 /*
208 * Move cursor up 'curnum' lines
209 */
210 EXPORT void
vup(wp)211 vup(wp)
212 ewin_t *wp;
213 {
214 epos_t savedot = wp->dot;
215
216 /*
217 * Count == 1 moves to the begining of current line.
218 * The rest moves back for 'curnum' lines.
219 */
220 wp->dot = revline(wp, wp->dot, wp->curnum+1);
221 wp->dot = findcol(wp, wp->column, wp->dot);
222
223 if (wp->dosmode && wp->dot >= 1 && dosnl(wp, wp->dot -1))
224 wp->dot -= 1;
225
226 wp->eflags &= ~COLUPDATE;
227 if (savedot == wp->dot)
228 ringbell();
229 }
230
231 /*
232 * Set mark, then move cursor up 'curnum' lines
233 */
234 EXPORT void
vsup(wp)235 vsup(wp)
236 ewin_t *wp;
237 {
238 setmark(wp, wp->dot);
239 vup(wp);
240 }
241
242 /*
243 * Move cursor up 'curnum' paragraphs
244 */
245 EXPORT void
vpup(wp)246 vpup(wp)
247 ewin_t *wp;
248 {
249 if (wp->dot == 0) {
250 ringbell();
251 } else {
252 #ifdef _old_revpara_
253 /*
254 * Count == 1 moves to the begining of current paragraph.
255 * The rest moves back for 'curnum' paragraphs.
256 */
257 wp->dot = revpara(wp, wp->dot, wp->curnum+1);
258 #else
259 wp->dot = revpara(wp, wp->dot, wp->curnum);
260 #endif
261 }
262 }
263
264 /*
265 * Set mark, then move cursor up 'curnum' paragraphs
266 */
267 EXPORT void
vspup(wp)268 vspup(wp)
269 ewin_t *wp;
270 {
271 setmark(wp, wp->dot);
272 vpup(wp);
273 }
274
275 /*
276 * Move cursor down 'curnum' lines
277 */
278 EXPORT void
vdown(wp)279 vdown(wp)
280 ewin_t *wp;
281 {
282 if (wp->dot == wp->eof) {
283 ringbell();
284 } else {
285 wp->dot = forwline(wp, wp->dot, wp->curnum);
286 wp->dot = findcol(wp, wp->column, wp->dot);
287
288 if (wp->dosmode && (wp->eof - wp->dot) >= 1 && dosnl(wp, wp->dot -1))
289 wp->dot -= 1;
290 }
291 wp->eflags &= ~COLUPDATE;
292 }
293
294 /*
295 * Set mark, then move cursor down 'curnum' lines
296 */
297 EXPORT void
vsdown(wp)298 vsdown(wp)
299 ewin_t *wp;
300 {
301 setmark(wp, wp->dot);
302 vdown(wp);
303 }
304
305 /*
306 * Move cursor down 'curnum' paragraphs
307 */
308 EXPORT void
vpdown(wp)309 vpdown(wp)
310 ewin_t *wp;
311 {
312 if (wp->dot == wp->eof) {
313 ringbell();
314 } else {
315 wp->dot = forwpara(wp, wp->dot, wp->curnum);
316 }
317 }
318
319 /*
320 * Set mark, then move cursor down 'curnum' paragraphs
321 */
322 EXPORT void
vspdwn(wp)323 vspdwn(wp)
324 ewin_t *wp;
325 {
326 setmark(wp, wp->dot);
327 vpdown(wp);
328 }
329
330 /*
331 * Move cursor up 'curnum' pages
332 */
333 EXPORT void
vpageup(wp)334 vpageup(wp)
335 ewin_t *wp;
336 {
337 if (wp->dot == 0) {
338 ringbell();
339 } else {
340 /*cdbg("up: %d", wp->curnum * (wp->psize + 1) - wp->optline);*/
341 wp->dot = revline(wp, wp->window, wp->curnum * (wp->psize + 1) - wp->optline);
342 #ifdef __comment__
343 /* XXX ??? */
344 wp->dot = revline(wp, wp->dot, wp->curnum * (wp->psize + 1));
345 wp->window = revline(wp, wp->window, wp->curnum * (wp->psize + 1));
346 #endif
347 }
348 }
349
350 /*
351 * Set mark, then move cursor up 'curnum' pages
352 */
353 EXPORT void
vspageup(wp)354 vspageup(wp)
355 ewin_t *wp;
356 {
357 setmark(wp, wp->dot);
358 vpageup(wp);
359 }
360
361 /*
362 * Move cursor down 'curnum' pages
363 */
364 EXPORT void
vpagedwn(wp)365 vpagedwn(wp)
366 ewin_t *wp;
367 {
368 if (wp->dot >= wp->eof) {
369 ringbell();
370 } else {
371 /*cdbg("down: %d", wp->curnum * (wp->psize - 2) + wp->optline);*/
372 wp->dot = forwline(wp, wp->window, wp->curnum * (wp->psize - 2) + wp->optline);
373 #ifdef __comment__
374 /* XXX ??? */
375 wp->dot = forwline(wp, wp->dot, wp->curnum * (wp->psize - 1));
376 wp->window = forwline(wp, wp->window, wp->curnum * (wp->psize - 1));
377 #endif
378 }
379 }
380
381 /*
382 * Set mark, then move cursor down 'curnum' pages
383 */
384 EXPORT void
vspagedwn(wp)385 vspagedwn(wp)
386 ewin_t *wp;
387 {
388 setmark(wp, wp->dot);
389 vpagedwn(wp);
390 }
391
392 /*
393 * Move cursor to the end of current line,
394 * then go back 'curnum' characters
395 *
396 * As the search operation returns the position of the '\n',
397 * we must go back one character even if 'curnum' is '1'.
398 */
399 EXPORT void
vend(wp)400 vend(wp)
401 ewin_t *wp;
402 {
403 wp->dot = search(wp, wp->dot, UC "\n", 1, 0);
404 if (wp->dot > wp->eof)
405 wp->dot = wp->eof + 1;
406
407 vrev(wp);
408 }
409
410 /*
411 * Set mark, then move cursor to the end of current line,
412 * then go back 'curnum' characters
413 */
414 EXPORT void
vsend(wp)415 vsend(wp)
416 ewin_t *wp;
417 {
418 setmark(wp, wp->dot);
419 vend(wp);
420 }
421
422 /*
423 * Move cursor to the end of current paragraph,
424 * then go back 'curnum-1' words
425 */
426 EXPORT void
vpend(wp)427 vpend(wp)
428 ewin_t *wp;
429 {
430 wp->dot = forwpara(wp, wp->dot, (ecnt_t)1);
431 /*
432 * Go back one for the overshoot and one for the space before
433 */
434 if (wp->dot < wp->eof)
435 wp->dot -= 2;
436 wp->curnum--;
437 if (wp->curnum > 0)
438 vwrev(wp);
439 }
440
441 /*
442 * Set mark, then move cursor to the end of current paragraph,
443 * then go back 'curnum-1' words
444 */
445 EXPORT void
vspend(wp)446 vspend(wp)
447 ewin_t *wp;
448 {
449 setmark(wp, wp->dot);
450 vpend(wp);
451 }
452
453 /*
454 * Move cursor to the beginning of current line,
455 * then go forwards 'curnum' characters
456 */
457 EXPORT void
vbegin(wp)458 vbegin(wp)
459 ewin_t *wp;
460 {
461 wp->dot = revline(wp, wp->dot, (ecnt_t)1);
462 wp->curnum--;
463 vforw(wp);
464 }
465
466 /*
467 * Set mark, then move cursor to the beginning of current line,
468 * then go forwards 'curnum' characters
469 */
470 EXPORT void
vsbegin(wp)471 vsbegin(wp)
472 ewin_t *wp;
473 {
474 setmark(wp, wp->dot);
475 vbegin(wp);
476 }
477
478 /*
479 * Move cursor to the beginning of current paragraph,
480 * then go forwards 'curnum-1' words
481 */
482 EXPORT void
vpbegin(wp)483 vpbegin(wp)
484 ewin_t *wp;
485 {
486 wp->dot = revpara(wp, wp->dot, (ecnt_t)1);
487 wp->curnum--;
488 vwforw(wp);
489 }
490
491 /*
492 * Set mark, then move cursor to the beginning of current paragraph,
493 * then go forwards 'curnum-1' words
494 */
495 EXPORT void
vspbegin(wp)496 vspbegin(wp)
497 ewin_t *wp;
498 {
499 setmark(wp, wp->dot);
500 vpbegin(wp);
501 }
502
503 /*
504 * Move cursor to the beginning of the file
505 *
506 * If 'curnum' if > 0, move cursor to line 'curnum' from top of file
507 */
508 EXPORT void
vtop(wp)509 vtop(wp)
510 ewin_t *wp;
511 {
512 if (wp->dot == 0 && wp->curnum == 1)
513 ringbell();
514 wp->dot = forwline(wp, (epos_t)0, wp->curnum-1);
515 }
516
517 /*
518 * Set mark, then move cursor to the beginning of the file
519 *
520 * If 'curnum' if > 0, move cursor to line 'curnum' from top of file
521 */
522 EXPORT void
vstop(wp)523 vstop(wp)
524 ewin_t *wp;
525 {
526 setmark(wp, wp->dot);
527 vtop(wp);
528 }
529
530 /*
531 * Move cursor to the end of the file
532 *
533 * If 'curnum' if > 0, move cursor backwards 'curnum' lines from end of file
534 */
535 EXPORT void
vbottom(wp)536 vbottom(wp)
537 ewin_t *wp;
538 {
539 if (wp->curnum <= 1) {
540 if (wp->dot == wp->eof)
541 ringbell();
542 else
543 wp->dot = wp->eof;
544 } else {
545 wp->dot = revline(wp, wp->eof, wp->curnum);
546 wp->curnum = 1;
547 vend(wp);
548 }
549 }
550
551 /*
552 * Move cursor to the end of the file
553 *
554 * If 'curnum' if > 0, move cursor backwards 'curnum' lines from end of file
555 */
556 EXPORT void
vsbottom(wp)557 vsbottom(wp)
558 ewin_t *wp;
559 {
560 setmark(wp, wp->dot);
561 vbottom(wp);
562 }
563
564 /*
565 * Adjust window
566 */
567 EXPORT void
vadjwin(wp)568 vadjwin(wp)
569 ewin_t *wp;
570 {
571 setwindow(wp);
572 }
573
574 /*
575 * Redisplay window content
576 */
577 EXPORT void
vredisp(wp)578 vredisp(wp)
579 ewin_t *wp;
580 {
581 CLEAR_SCREEN(wp);
582 refreshmsg(wp);
583 MOVE_CURSOR(wp, 1, 0);
584 typescreen(wp, wp->window, 0, wp->eof);
585 }
586
587 /*
588 * Make current line be the top line in window
589 */
590 EXPORT void
vltopwin(wp)591 vltopwin(wp)
592 ewin_t *wp;
593 {
594 wp->dot = forwline(wp, wp->dot, (ecnt_t)(wp->optline -1));
595 update(wp);
596 setwindow(wp);
597 }
598
599 char brack[] = "([{<)]}>";
600 char *brclose = &brack[4];
601 struct br {
602 Uchar *br_type;
603 Uchar *br_pat;
604 } br[] = {
605 {UC "()", UC "[()]"},
606 {UC "[]", UC "[\\[\\]]"},
607 {UC "{}", UC "[{}]"},
608 {UC "<>", UC "[<>]"},
609 };
610
611 /*
612 * Find matching bracket
613 */
614 LOCAL epos_t
srchbrack(wp,begin,ch,sfunc)615 srchbrack(wp, begin, ch, sfunc)
616 ewin_t *wp;
617 epos_t begin;
618 Uchar ch;
619 epos_t (*sfunc) __PR((ewin_t *wp, epos_t, Uchar *, int, int));
620 {
621 Uchar b[2];
622 Uchar *spat;
623 int plen;
624 int n = 1;
625 struct br *brp = br;
626
627 while (!strchr(C brp->br_type, (char)ch))
628 brp++;
629 spat = brp->br_pat;
630 plen = strlen(C spat);
631
632 begin++;
633 while (n > 0) {
634 begin = (*sfunc)(wp, begin, spat, plen, 0);
635 if (begin > wp->eof)
636 return (begin);
637 if (extract(wp, begin-1, b, 1) != 1)
638 return (wp->eof+2);
639 /* writeerr("C: '%c' p %d", b[0], begin);sleep(1);*/
640 if (b[0] == ch)
641 n++;
642 else
643 n--;
644 }
645 return (--begin);
646 }
647
648 /*
649 * Search for matching backet, check if we need to search forwards or backwards
650 */
651 LOCAL epos_t
searchbrack(wp,begin,ch)652 searchbrack(wp, begin, ch)
653 ewin_t *wp;
654 epos_t begin;
655 Uchar ch;
656 {
657 BOOL omagic;
658
659 omagic = wp->magic;
660 wp->magic = TRUE;
661 if (strchr(brclose, (char)ch)) {
662 begin = srchbrack(wp, begin, ch, reverse);
663 } else {
664 begin = srchbrack(wp, begin, ch, search);
665 }
666 wp->magic = omagic;
667 return (begin);
668 }
669
670 /*
671 * Move cursor to matching bracket
672 */
673 EXPORT void
vbrack(wp)674 vbrack(wp)
675 ewin_t *wp;
676 {
677 Uchar b[2];
678 epos_t newdot;
679
680 if (extract(wp, wp->dot, b, 1) != 1 || !strchr(brack, (char)b[0])) {
681 ringbell();
682 } else {
683 newdot = searchbrack(wp, wp->dot, b[0]);
684 if (newdot > wp->eof)
685 not_found(wp);
686 else
687 wp->dot = newdot;
688 }
689 }
690