[PATCH] Screen buffers ESC keypresses indefinitely since sgr support
[screen.git] / src / mark.c
blob685429f336bd83e72d0e50a505c0444b16323355
1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include "config.h"
31 #include "mark.h"
33 #include <sys/types.h>
34 #include <ctype.h>
35 #include <stdbool.h>
36 #include <stdint.h>
37 #include <stdbool.h>
39 #include "screen.h"
41 #include "encoding.h"
42 #include "fileio.h"
43 #include "process.h"
44 #include "search.h"
45 #include "winmsg.h"
48 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
50 * WARNING: these routines use the global variables "fore" and
51 * "flayer" to make things easier.
53 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
56 static int is_letter(int);
57 static void nextword(int *, int *, int, int);
58 static int linestart(int);
59 static int lineend(int);
60 static int rem(int, int, int, int, int, char *, int);
61 static bool eq(int, int);
62 static int MarkScrollDownDisplay(int);
63 static int MarkScrollUpDisplay(int);
65 static void MarkProcess(char **, size_t *);
66 static void MarkAbort(void);
67 static void MarkRedisplayLine(int, int, int, int);
69 bool compacthist = false;
70 bool join_with_cr = false;
71 bool pastefont = true;
73 const struct LayFuncs MarkLf = {
74 MarkProcess,
75 MarkAbort,
76 MarkRedisplayLine,
77 DefClearLine,
78 DefResize,
79 DefRestore,
80 NULL
83 unsigned char mark_key_tab[256]; /* this array must be initialised first! */
85 static struct markdata *markdata;
88 * VI like is_letter: 0 - whitespace
89 * 1 - letter
90 * 2 - other
92 static int is_letter(int c)
94 if (isalnum(c) ||
95 c == '_' || c == '.' || c == '@' || c == ':' || c == '%' || c == '!' || c == '-' || c == '+')
96 /* thus we can catch email-addresses as a word :-) */
97 return 1;
98 else if (c != ' ')
99 return 2;
100 return 0;
103 static int linestart(int y)
105 int x;
106 uint32_t *i;
108 for (x = markdata->left_mar, i = WIN(y)->image + x; x < fore->w_width - 1; x++)
109 if (*i++ != ' ')
110 break;
111 if (x == fore->w_width - 1)
112 x = markdata->left_mar;
113 return x;
116 static int lineend(int y)
118 int x;
119 uint32_t *i;
121 for (x = markdata->right_mar, i = WIN(y)->image + x; x >= 0; x--)
122 if (*i-- != ' ')
123 break;
124 if (x < 0)
125 x = markdata->left_mar;
126 return x;
130 * nextchar sets *xp to the num-th occurrence of the target in the line.
132 * Returns -1 if the target doesn't appear num times, 0 otherwise.
134 static int nextchar(int *xp, int *yp, int direction, char target, int num)
136 int width; /* width of the current window. */
137 int x; /* x coordinate of the current cursor position. */
138 int step; /* amount to increment x (+1 or -1) */
139 int adjust; /* Final adjustment of cursor position. */
140 char *displayed_line; /* Line in which search takes place. */
142 x = *xp;
143 step = 1;
144 adjust = 0;
145 width = fore->w_width;
146 displayed_line = (char *)WIN(*yp)->image;
148 switch (direction) {
149 case 't':
150 adjust = -1; /* fall through */
151 case 'f':
152 step = 1;
153 break;
154 case 'T':
155 adjust = 1; /* fall through */
156 case 'F':
157 step = -1;
158 break;
161 x += step;
163 for (; x >= 0 && x <= width; x += step) {
164 if (displayed_line[x] == target) {
165 if (--num == 0) {
166 *xp = x + adjust;
167 return 0;
171 return -1;
175 * nextword calculates the cursor position of the num'th word.
176 * If the cursor is on a word, it counts as the first.
177 * NW_BACK: search backward
178 * NW_ENDOFWORD: find the end of the word
179 * NW_MUSTMOVE: move at least one char
180 * NW_BIG: match WORDs not words
183 #define NW_BACK (1<<0)
184 #define NW_ENDOFWORD (1<<1)
185 #define NW_MUSTMOVE (1<<2)
186 #define NW_BIG (1<<3)
188 static void nextword(int *xp, int *yp, int flags, int num)
190 int xx = fore->w_width, yy = fore->w_histheight + fore->w_height;
191 int sx, oq, q, x, y;
192 struct mline *ml;
194 x = *xp;
195 y = *yp;
196 sx = (flags & NW_BACK) ? -1 : 1;
197 if ((flags & NW_ENDOFWORD) && (flags & NW_MUSTMOVE))
198 x += sx;
199 ml = WIN(y);
200 for (oq = -1;; x += sx, oq = q) {
201 if (x >= xx || x < 0)
202 q = 0;
203 else if (flags & NW_BIG)
204 q = ml->image[x] == ' ';
205 else
206 q = is_letter(ml->image[x]);
207 if (oq >= 0 && oq != q) {
208 if (oq == 0 || !(flags & NW_ENDOFWORD))
209 *xp = x;
210 else
211 *xp = x - sx;
212 *yp = y;
213 if ((!(flags & NW_ENDOFWORD) && q) || ((flags & NW_ENDOFWORD) && oq)) {
214 if (--num <= 0)
215 return;
218 if (x == xx) {
219 x = -1;
220 if (++y >= yy)
221 return;
222 ml = WIN(y);
223 } else if (x < 0) {
224 x = xx;
225 if (--y < 0)
226 return;
227 ml = WIN(y);
233 * y1, y2 are WIN coordinates
235 * redisplay: 0 - just copy
236 * 1 - redisplay + copy
237 * 2 - count + copy, don't redisplay
240 static int rem(int x1, int y1, int x2, int y2, int redisplay, char *pt, int yend)
242 int i, j, from, to, ry;
243 int l = 0;
244 uint32_t *im;
245 struct mline *ml;
246 int font;
247 uint32_t *fo;
249 markdata->second = 0;
250 if (y2 < y1 || ((y2 == y1) && (x2 < x1))) {
251 i = y2;
252 y2 = y1;
253 y1 = i;
254 i = x2;
255 x2 = x1;
256 x1 = i;
258 ry = y1 - markdata->hist_offset;
260 i = y1;
261 if (redisplay != 2 && pt == NULL && ry < 0) {
262 i -= ry;
263 ry = 0;
265 for (; i <= y2; i++, ry++) {
266 if (redisplay != 2 && pt == NULL && ry > yend)
267 break;
268 ml = WIN(i);
269 from = (i == y1) ? x1 : 0;
270 if (from < markdata->left_mar)
271 from = markdata->left_mar;
272 for (to = fore->w_width, im = ml->image + to; to >= 0; to--)
273 if (*im-- != ' ')
274 break;
275 if (i == y2 && x2 < to)
276 to = x2;
277 if (to > markdata->right_mar)
278 to = markdata->right_mar;
279 if (redisplay == 1 && from <= to && ry >= 0 && ry <= yend)
280 MarkRedisplayLine(ry, from, to, 0);
281 if (redisplay != 2 && pt == NULL) /* don't count/copy */
282 continue;
283 j = from;
284 if (dw_right(ml, j, fore->w_encoding))
285 j--;
286 im = ml->image + j;
287 fo = ml->font + j;
288 font = ASCII;
289 for (; j <= to; j++) {
290 uint32_t c = *im++;
291 uint32_t cf = *fo++;
292 if (fore->w_encoding == UTF8) {
293 c |= cf << 8;
294 if (c == UCS_HIDDEN)
295 continue;
296 c = ToUtf8_comb(pt, c);
297 l += c;
298 if (pt)
299 pt += c;
300 continue;
302 if (is_dw_font(cf)) {
303 c = c << 8 | *im++;
304 fo++;
305 j++;
307 if (pastefont) {
308 c = EncodeChar(pt, c | cf << 16, fore->w_encoding, &font);
309 l += c;
310 if (pt)
311 pt += c;
312 continue;
314 if (pt)
315 *pt++ = c;
316 l++;
318 if (pastefont && font != ASCII) {
319 if (pt) {
320 strncpy(pt, "\033(B", 4);
321 pt += 3;
323 l += 3;
325 if (i != y2 && (to != fore->w_width - 1 || ml->image[to + 1] == ' ')) {
327 * this code defines, what glues lines together
329 switch (markdata->nonl) {
330 case 0: /* lines separated by newlines */
331 if (pt)
332 *pt++ = '\r';
333 l++;
334 if (join_with_cr) {
335 if (pt)
336 *pt++ = '\n';
337 l++;
339 break;
340 case 1: /* nothing to separate lines */
341 break;
342 case 2: /* lines separated by blanks */
343 if (pt)
344 *pt++ = ' ';
345 l++;
346 break;
347 case 3: /* seperate by comma, for csh junkies */
348 if (pt)
349 *pt++ = ',';
350 l++;
351 break;
355 return l;
358 /* Check if two chars are identical. All digits are treated
359 * as same. Used for GetHistory()
362 static bool eq(int a, int b)
364 if (a == b)
365 return true;
366 if (a == 0 || b == 0)
367 return true;
368 if (isdigit(a) && isdigit(b))
369 return true;
370 return false;
373 /**********************************************************************/
375 int GetHistory(void)
376 { /* return value 1 if copybuffer changed */
377 int i = 0, q = 0, xx, yy, x, y;
378 uint32_t *linep;
379 struct mline *ml;
381 x = fore->w_x;
382 if (x >= fore->w_width)
383 x = fore->w_width - 1;
384 y = fore->w_y + fore->w_histheight;
385 ml = WIN(y);
386 for (xx = x - 1, linep = ml->image + xx; xx >= 0; xx--)
387 if ((q = *linep--) != ' ')
388 break;
389 for (yy = y - 1; yy >= 0; yy--) {
390 ml = WIN(yy);
391 linep = ml->image;
392 if (xx < 0 || eq(linep[xx], q)) { /* line is matching... */
393 for (i = fore->w_width - 1, linep += i; i >= x; i--)
394 if (*linep-- != ' ')
395 break;
396 if (i >= x)
397 break;
400 if (yy < 0)
401 return 0;
402 if (D_user->u_plop.buf)
403 UserFreeCopyBuffer(D_user);
404 if ((D_user->u_plop.buf = malloc((unsigned)(i - x + 2))) == NULL) {
405 LMsg(0, "Not enough memory... Sorry.");
406 return 0;
408 memmove(D_user->u_plop.buf, (char *)linep - i + x + 1, i - x + 1);
409 D_user->u_plop.len = i - x + 1;
410 D_user->u_plop.enc = fore->w_encoding;
411 return 1;
414 /**********************************************************************/
416 void MarkRoutine(void)
418 int x, y;
420 if (InitOverlayPage(sizeof(struct markdata), &MarkLf, 1))
421 return;
422 flayer->l_encoding = fore->w_encoding;
423 flayer->l_mode = 1;
424 markdata = (struct markdata *)flayer->l_data;
425 markdata->md_user = D_user; /* XXX: Correct? */
426 markdata->md_window = fore;
427 markdata->second = 0;
428 markdata->rep_cnt = 0;
429 markdata->append_mode = 0;
430 markdata->write_buffer = 0;
431 markdata->nonl = 0;
432 markdata->left_mar = 0;
433 markdata->right_mar = fore->w_width - 1;
434 markdata->hist_offset = fore->w_histheight;
435 x = fore->w_x;
436 y = D2W(fore->w_y);
437 if (x >= fore->w_width)
438 x = fore->w_width - 1;
440 LGotoPos(flayer, x, W2D(y));
441 LMsg(0, "Copy mode - Column %d Line %d(+%d) (%d,%d)",
442 x + 1, W2D(y + 1), fore->w_histheight, fore->w_width, fore->w_height);
443 markdata->cx = markdata->x1 = x;
444 markdata->cy = markdata->y1 = y;
445 flayer->l_x = x;
446 flayer->l_y = W2D(y);
449 static void MarkProcess(char **inbufp, size_t *inlenp)
451 char *inbuf, *pt;
452 int inlen;
453 int cx, cy, x2, y2, j, yend;
454 int newcopylen = 0, od;
455 int in_mark;
456 int rep_cnt;
457 struct acluser *md_user;
460 char *extrap = 0, extrabuf[100];
463 markdata = (struct markdata *)flayer->l_data;
464 fore = markdata->md_window;
465 md_user = markdata->md_user;
466 if (inbufp == NULL) {
467 MarkAbort();
468 return;
471 LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
472 inbuf = *inbufp;
473 inlen = *inlenp;
474 pt = inbuf;
475 in_mark = 1;
476 while (in_mark && (inlen /* || extrap */ )) {
477 unsigned char ch = (unsigned char)*pt++;
478 inlen--;
479 if (flayer->l_mouseevent.start) {
480 int r = LayProcessMouse(flayer, ch);
481 if (r == -1)
482 LayProcessMouseSwitch(flayer, 0);
483 else {
484 if (r)
485 ch = 0222;
486 else
487 continue;
490 od = mark_key_tab[(int)ch];
491 rep_cnt = markdata->rep_cnt;
492 if (isdigit(od) && !markdata->f_cmd.flag) {
493 if (rep_cnt < 1001 && (od != '0' || rep_cnt != 0)) {
494 markdata->rep_cnt = 10 * rep_cnt + od - '0';
495 continue;
497 * Now what is that 1001 here? Well, we have a screen with
498 * 25 * 80 = 2000 characters. Movement is at most across the full
499 * screen. This we do with word by word movement, as character by
500 * character movement never steps over line boundaries. The most words
501 * we can place on the screen are 1000 single letter words. Thus 1001
502 * is sufficient. Users with bigger screens never write in single letter
503 * words, as they should be more advanced. jw.
504 * Oh, wrong. We still give even the experienced user a factor of ten.
508 cx = markdata->cx;
509 cy = markdata->cy;
511 if (markdata->f_cmd.flag) {
512 markdata->f_cmd.flag = 0;
513 markdata->rep_cnt = 0;
515 if (isgraph(od)) {
516 markdata->f_cmd.target = od;
517 rep_cnt = (rep_cnt) ? rep_cnt : 1;
518 nextchar(&cx, &cy, markdata->f_cmd.direction, od, rep_cnt);
519 revto(cx, cy);
520 continue;
524 processchar:
525 switch (od) {
526 case 'f': /* fall through */
527 case 'F': /* fall through */
528 case 't': /* fall through */
529 case 'T': /* fall through */
531 * Set f_cmd to do a search on the next key stroke.
532 * If we break, rep_cnt will be reset, so we
533 * continue instead. It might be cleaner to
534 * store the rep_count in f_cmd and
535 * break here so later followon code will be
536 * hit.
538 markdata->f_cmd.flag = 1;
539 markdata->f_cmd.direction = od;
540 continue;
541 case ';':
542 case ',':
543 if (!markdata->f_cmd.target)
544 break;
545 if (!rep_cnt)
546 rep_cnt = 1;
547 nextchar(&cx, &cy,
548 od == ';' ? markdata->f_cmd.direction : (markdata->f_cmd.direction ^ 0x20),
549 markdata->f_cmd.target, rep_cnt);
550 revto(cx, cy);
551 break;
552 case 'o':
553 case 'x':
554 if (!markdata->second)
555 break;
556 markdata->cx = markdata->x1;
557 markdata->cy = markdata->y1;
558 markdata->x1 = cx;
559 markdata->y1 = cy;
560 revto(markdata->cx, markdata->cy);
561 break;
562 case '\014': /* CTRL-L Redisplay */
563 Redisplay(0);
564 LGotoPos(flayer, cx, W2D(cy));
565 break;
566 case 0202: /* M-C-b */
567 case '\010': /* CTRL-H Backspace */
568 case 'h':
569 if (rep_cnt == 0)
570 rep_cnt = 1;
571 revto(cx - rep_cnt, cy);
572 break;
573 case 0216: /* M-C-p */
574 case '\016': /* CTRL-N */
575 case 'j':
576 if (rep_cnt == 0)
577 rep_cnt = 1;
578 revto(cx, cy + rep_cnt);
579 break;
580 case '+':
581 if (rep_cnt == 0)
582 rep_cnt = 1;
583 j = cy + rep_cnt;
584 if (j > fore->w_histheight + fore->w_height - 1)
585 j = fore->w_histheight + fore->w_height - 1;
586 revto(linestart(j), j);
587 break;
588 case '-':
589 if (rep_cnt == 0)
590 rep_cnt = 1;
591 cy -= rep_cnt;
592 if (cy < 0)
593 cy = 0;
594 revto(linestart(cy), cy);
595 break;
596 case '^':
597 revto(linestart(cy), cy);
598 break;
599 case '\n':
600 revto(markdata->left_mar, cy + 1);
601 break;
602 case 0220: /* M-C-p */
603 case '\020': /* CTRL-P */
604 case 'k':
605 if (rep_cnt == 0)
606 rep_cnt = 1;
607 revto(cx, cy - rep_cnt);
608 break;
609 case 0206: /* M-C-f */
610 case 'l':
611 if (rep_cnt == 0)
612 rep_cnt = 1;
613 revto(cx + rep_cnt, cy);
614 break;
615 case '\001': /* CTRL-A from tcsh/emacs */
616 case '0':
617 revto(markdata->left_mar, cy);
618 break;
619 case '\004': /* CTRL-D down half screen */
620 if (rep_cnt == 0)
621 rep_cnt = (fore->w_height + 1) >> 1;
622 revto_line(cx, cy + rep_cnt, W2D(cy));
623 break;
624 case '$':
625 revto(lineend(cy), cy);
626 break;
627 case '\022': /* CTRL-R emacs style backwards search */
628 ISearch(-1);
629 in_mark = 0;
630 break;
631 case '\023': /* CTRL-S emacs style search */
632 ISearch(1);
633 in_mark = 0;
634 break;
635 case '\025': /* CTRL-U up half screen */
636 if (rep_cnt == 0)
637 rep_cnt = (fore->w_height + 1) >> 1;
638 revto_line(cx, cy - rep_cnt, W2D(cy));
639 break;
640 case '\007': /* CTRL-G show cursorpos */
641 if (markdata->left_mar == 0 && markdata->right_mar == fore->w_width - 1)
642 LMsg(0, "Column %d Line %d(+%d)", cx + 1, W2D(cy) + 1, markdata->hist_offset);
643 else
644 LMsg(0, "Column %d(%d..%d) Line %d(+%d)", cx + 1,
645 markdata->left_mar + 1, markdata->right_mar + 1, W2D(cy) + 1,
646 markdata->hist_offset);
647 break;
648 case '\002': /* CTRL-B back one page */
649 if (rep_cnt == 0)
650 rep_cnt = 1;
651 rep_cnt *= fore->w_height;
652 revto(cx, cy - rep_cnt);
653 break;
654 case '\006': /* CTRL-F forward one page */
655 if (rep_cnt == 0)
656 rep_cnt = 1;
657 rep_cnt *= fore->w_height;
658 revto(cx, cy + rep_cnt);
659 break;
660 case '\005': /* CTRL-E scroll up */
661 if (rep_cnt == 0)
662 rep_cnt = 1;
663 MarkScrollUpDisplay(rep_cnt);
664 if (cy < D2W(0))
665 revto(cx, D2W(0));
666 else
667 LGotoPos(flayer, cx, W2D(cy));
668 break;
669 case '\031': /* CTRL-Y scroll down */
670 if (rep_cnt == 0)
671 rep_cnt = 1;
672 MarkScrollDownDisplay(rep_cnt);
673 if (cy > D2W(fore->w_height - 1))
674 revto(cx, D2W(fore->w_height - 1));
675 else
676 LGotoPos(flayer, cx, W2D(cy));
677 break;
678 case '@':
679 /* it may be useful to have a key that does nothing */
680 break;
681 case '%':
682 /* rep_cnt is a percentage for the history buffer */
683 if (rep_cnt < 0)
684 rep_cnt = 0;
685 if (rep_cnt > 100)
686 rep_cnt = 100;
687 revto_line(markdata->left_mar,
688 fore->w_histheight - fore->w_scrollback_height +
689 (int)(rep_cnt * (fore->w_scrollback_height + fore->w_height) / 100.0),
690 (fore->w_height - 1) / 2);
691 break;
692 case 0201:
693 case 'g':
694 rep_cnt = 1;
695 /* FALLTHROUGH */
696 case 0205:
697 case 'G':
698 /* rep_cnt is here the WIN line number */
699 if (rep_cnt == 0)
700 rep_cnt = fore->w_histheight + fore->w_height;
701 revto_line(markdata->left_mar, --rep_cnt, (fore->w_height - 1) / 2);
702 break;
703 case 'H':
704 revto(markdata->left_mar, D2W(0));
705 break;
706 case 'M':
707 revto(markdata->left_mar, D2W((fore->w_height - 1) / 2));
708 break;
709 case 'L':
710 revto(markdata->left_mar, D2W(fore->w_height - 1));
711 break;
712 case '|':
713 revto(--rep_cnt, cy);
714 break;
715 case 'w':
716 if (rep_cnt == 0)
717 rep_cnt = 1;
718 nextword(&cx, &cy, NW_MUSTMOVE, rep_cnt);
719 revto(cx, cy);
720 break;
721 case 'e':
722 case 'E':
723 if (rep_cnt == 0)
724 rep_cnt = 1;
725 nextword(&cx, &cy, NW_ENDOFWORD | NW_MUSTMOVE | (od == 'E' ? NW_BIG : 0), rep_cnt);
726 revto(cx, cy);
727 break;
728 case 'b':
729 case 'B':
730 if (rep_cnt == 0)
731 rep_cnt = 1;
732 nextword(&cx, &cy, NW_BACK | NW_ENDOFWORD | NW_MUSTMOVE | (od == 'B' ? NW_BIG : 0), rep_cnt);
733 revto(cx, cy);
734 break;
735 case 'a':
736 markdata->append_mode = 1 - markdata->append_mode;
737 LMsg(0, (markdata->append_mode) ? ":set append" : ":set noappend");
738 break;
739 case 'v':
740 case 'V':
741 /* this sets start column to column 9 for VI :set nu users */
742 if (markdata->left_mar == 8)
743 rep_cnt = 1;
744 else
745 rep_cnt = 9;
746 /* FALLTHROUGH */
747 case 'c':
748 case 'C':
749 /* set start column (c) and end column (C) */
750 if (markdata->second) {
751 rem(markdata->x1, markdata->y1, cx, cy, 1, NULL, fore->w_height - 1); /* Hack */
752 markdata->second = 1; /* rem turns off second */
754 rep_cnt--;
755 if (rep_cnt < 0)
756 rep_cnt = cx;
757 if (od != 'C') {
758 markdata->left_mar = rep_cnt;
759 if (markdata->left_mar > markdata->right_mar)
760 markdata->left_mar = markdata->right_mar;
761 } else {
762 markdata->right_mar = rep_cnt;
763 if (markdata->left_mar > markdata->right_mar)
764 markdata->right_mar = markdata->left_mar;
766 if (markdata->second) {
767 markdata->cx = markdata->x1;
768 markdata->cy = markdata->y1;
769 revto(cx, cy);
771 if (od == 'v' || od == 'V')
772 LMsg(0, (markdata->left_mar != 8) ? ":set nonu" : ":set nu");
773 break;
774 case 'J':
775 /* how do you join lines in VI ? */
776 markdata->nonl = (markdata->nonl + 1) % 4;
777 switch (markdata->nonl) {
778 case 0:
779 if (join_with_cr)
780 LMsg(0, "Multiple lines (CR/LF)");
781 else
782 LMsg(0, "Multiple lines (LF)");
783 break;
784 case 1:
785 LMsg(0, "Lines joined");
786 break;
787 case 2:
788 LMsg(0, "Lines joined with blanks");
789 break;
790 case 3:
791 LMsg(0, "Lines joined with comma");
792 break;
794 break;
795 case '/':
796 Search(1);
797 in_mark = 0;
798 break;
799 case '?':
800 Search(-1);
801 in_mark = 0;
802 break;
803 case 'n':
804 Search(0);
805 break;
806 case 'N':
807 markdata->isdir = -markdata->isdir;
808 Search(0);
809 markdata->isdir = -markdata->isdir;
810 break;
811 case 'y':
812 case 'Y':
813 if (markdata->second == 0) {
814 revto(linestart(cy), cy);
815 markdata->second++;
816 cx = markdata->x1 = markdata->cx;
817 cy = markdata->y1 = markdata->cy;
819 if (--rep_cnt > 0)
820 revto(cx, cy + rep_cnt);
821 revto(lineend(markdata->cy), markdata->cy);
822 if (od == 'y')
823 break;
824 /* FALLTHROUGH */
825 case 'W':
826 if (od == 'W') {
827 if (rep_cnt == 0)
828 rep_cnt = 1;
829 if (!markdata->second) {
830 nextword(&cx, &cy, NW_BACK | NW_ENDOFWORD, 1);
831 revto(cx, cy);
832 markdata->second++;
833 cx = markdata->x1 = markdata->cx;
834 cy = markdata->y1 = markdata->cy;
836 nextword(&cx, &cy, NW_ENDOFWORD, rep_cnt);
837 revto(cx, cy);
839 cx = markdata->cx;
840 cy = markdata->cy;
841 /* FALLTHROUGH */
842 case 'A':
843 if (od == 'A')
844 markdata->append_mode = 1;
845 /* FALLTHROUGH */
846 case '>':
847 if (od == '>')
848 markdata->write_buffer = 1;
849 /* FALLTHROUGH */
850 case ' ':
851 case '\r':
852 if (!markdata->second) {
853 markdata->second++;
854 markdata->x1 = cx;
855 markdata->y1 = cy;
856 revto(cx, cy);
857 LMsg(0, "First mark set - Column %d Line %d", cx + 1, W2D(cy) + 1);
858 break;
859 } else {
860 int append_mode = markdata->append_mode;
861 int write_buffer = markdata->write_buffer;
863 x2 = cx;
864 y2 = cy;
865 newcopylen = rem(markdata->x1, markdata->y1, x2, y2, 2, NULL, 0); /* count */
866 if (md_user->u_plop.buf && !append_mode)
867 UserFreeCopyBuffer(md_user);
868 yend = fore->w_height - 1;
869 if (fore->w_histheight - markdata->hist_offset < fore->w_height) {
870 markdata->second = 0;
871 yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
873 if (newcopylen > 0) {
874 /* the +3 below is for : cr + lf + \0 */
875 if (md_user->u_plop.buf)
876 md_user->u_plop.buf = realloc(md_user->u_plop.buf,
877 (unsigned)(md_user->u_plop.len +
878 newcopylen + 3));
879 else {
880 md_user->u_plop.len = 0;
881 md_user->u_plop.buf = malloc((unsigned)(newcopylen + 3));
883 if (!md_user->u_plop.buf) {
884 MarkAbort();
885 in_mark = 0;
886 LMsg(0, "Not enough memory... Sorry.");
887 md_user->u_plop.len = 0;
888 md_user->u_plop.buf = NULL;
889 break;
891 if (append_mode) {
892 switch (markdata->nonl) {
894 * this code defines, what glues lines together
896 case 0:
897 if (join_with_cr) {
898 md_user->u_plop.buf[md_user->u_plop.len] = '\r';
899 md_user->u_plop.len++;
901 md_user->u_plop.buf[md_user->u_plop.len] = '\n';
902 md_user->u_plop.len++;
903 break;
904 case 1:
905 break;
906 case 2:
907 md_user->u_plop.buf[md_user->u_plop.len] = ' ';
908 md_user->u_plop.len++;
909 break;
910 case 3:
911 md_user->u_plop.buf[md_user->u_plop.len] = ',';
912 md_user->u_plop.len++;
913 break;
916 md_user->u_plop.len += rem(markdata->x1, markdata->y1, x2, y2,
917 markdata->hist_offset == fore->w_histheight,
918 md_user->u_plop.buf + md_user->u_plop.len, yend);
919 md_user->u_plop.enc = fore->w_encoding;
921 if (markdata->hist_offset != fore->w_histheight) {
922 LAY_CALL_UP(LRefreshAll(flayer, 0));
924 ExitOverlayPage();
925 WindowChanged(fore, WINESC_COPY_MODE);
926 if (append_mode)
927 LMsg(0, "Appended %d characters to buffer", newcopylen);
928 else
929 LMsg(0, "Copied %zu characters into buffer", md_user->u_plop.len);
930 if (write_buffer)
931 WriteFile(md_user, NULL, DUMP_EXCHANGE);
932 in_mark = 0;
933 break;
936 case 0222:
937 if (flayer->l_mouseevent.start) {
938 int button = flayer->l_mouseevent.buffer[0];
939 if (button == 'a') {
940 /* Scroll down */
941 od = 'j';
942 } else if (button == '`') {
943 /* Scroll up */
944 od = 'k';
945 } else if (button == ' ') {
946 /* Left click */
947 cx = flayer->l_mouseevent.buffer[1];
948 cy = D2W(flayer->l_mouseevent.buffer[2]);
949 revto(cx, cy);
950 od = ' ';
951 } else
952 od = 0;
953 LayProcessMouseSwitch(flayer, 0);
954 if (od)
955 goto processchar;
956 } else
957 LayProcessMouseSwitch(flayer, 1);
958 break;
960 default:
961 MarkAbort();
962 LMsg(0, "Copy mode aborted");
963 in_mark = 0;
964 break;
966 if (in_mark) /* markdata may be freed */
967 markdata->rep_cnt = 0;
969 if (in_mark) {
970 flayer->l_x = markdata->cx;
971 flayer->l_y = W2D(markdata->cy);
973 *inbufp = pt;
974 *inlenp = inlen;
977 void revto(int tx, int ty)
979 revto_line(tx, ty, -1);
982 /* tx, ty: WINDOW, line: DISPLAY */
983 void revto_line(int tx, int ty, int line)
985 int fx, fy;
986 int x, y, t, revst, reven, qq, ff, tt, st, en, ce = 0;
987 int ystart = 0, yend = fore->w_height - 1;
988 int i, ry;
989 uint32_t *wi;
990 struct mline *ml;
991 struct mchar mc;
993 if (tx < 0)
994 tx = 0;
995 else if (tx > fore->w_width - 1)
996 tx = fore->w_width - 1;
997 if (ty < fore->w_histheight - fore->w_scrollback_height)
998 ty = fore->w_histheight - fore->w_scrollback_height;
999 else if (ty > fore->w_histheight + fore->w_height - 1)
1000 ty = fore->w_histheight + fore->w_height - 1;
1002 fx = markdata->cx;
1003 fy = markdata->cy;
1005 /* don't just move inside of a kanji, the user wants to see something */
1006 ml = WIN(ty);
1007 if (ty == fy && fx + 1 == tx && dw_right(ml, tx, fore->w_encoding) && tx < D_width - 1)
1008 tx++;
1009 if (ty == fy && fx - 1 == tx && dw_right(ml, fx, fore->w_encoding) && tx)
1010 tx--;
1012 markdata->cx = tx;
1013 markdata->cy = ty;
1016 * if we go to a position that is currently offscreen
1017 * then scroll the screen
1019 i = 0;
1020 if (line >= 0 && line < fore->w_height)
1021 i = W2D(ty) - line;
1022 else if (ty < markdata->hist_offset)
1023 i = ty - markdata->hist_offset;
1024 else if (ty > markdata->hist_offset + (fore->w_height - 1))
1025 i = ty - markdata->hist_offset - (fore->w_height - 1);
1026 if (i > 0)
1027 yend -= MarkScrollUpDisplay(i);
1028 else if (i < 0)
1029 ystart += MarkScrollDownDisplay(-i);
1031 if (markdata->second == 0) {
1032 flayer->l_x = tx;
1033 flayer->l_y = W2D(ty);
1034 LGotoPos(flayer, tx, W2D(ty));
1035 return;
1038 qq = markdata->x1 + markdata->y1 * fore->w_width;
1039 ff = fx + fy * fore->w_width; /* "from" offset in WIN coords */
1040 tt = tx + ty * fore->w_width; /* "to" offset in WIN coords */
1042 if (ff > tt) {
1043 st = tt;
1044 en = ff;
1045 x = tx;
1046 y = ty;
1047 } else {
1048 st = ff;
1049 en = tt;
1050 x = fx;
1051 y = fy;
1053 if (st > qq) {
1054 st++;
1055 x++;
1057 if (en < qq)
1058 en--;
1059 if (tt > qq) {
1060 revst = qq;
1061 reven = tt;
1062 } else {
1063 revst = tt;
1064 reven = qq;
1066 ry = y - markdata->hist_offset;
1067 if (ry < ystart) {
1068 y += (ystart - ry);
1069 x = 0;
1070 st = y * fore->w_width;
1071 ry = ystart;
1073 ml = WIN(y);
1074 for (t = st; t <= en; t++, x++) {
1075 if (x >= fore->w_width) {
1076 x = 0;
1077 y++, ry++;
1078 ml = WIN(y);
1080 if (ry > yend)
1081 break;
1082 if (t == st || x == 0) {
1083 wi = ml->image + fore->w_width;
1084 for (ce = fore->w_width; ce >= 0; ce--, wi--)
1085 if (*wi != ' ')
1086 break;
1088 if (x <= ce && x >= markdata->left_mar && x <= markdata->right_mar) {
1089 if (dw_right(ml, x, fore->w_encoding)) {
1090 if (t == revst)
1091 revst--;
1092 t--;
1093 x--;
1095 if (t >= revst && t <= reven) {
1096 mc = mchar_so;
1097 if (pastefont) {
1098 mc.font = ml->font[x];
1100 mc.image = ml->image[x];
1101 } else
1102 copy_mline2mchar(&mc, ml, x);
1103 if (dw_left(ml, x, fore->w_encoding)) {
1104 mc.mbcs = ml->image[x + 1];
1105 LPutChar(flayer, &mc, x, W2D(y));
1106 t++;
1108 LPutChar(flayer, &mc, x, W2D(y));
1109 if (dw_left(ml, x, fore->w_encoding))
1110 x++;
1113 flayer->l_x = tx;
1114 flayer->l_y = W2D(ty);
1115 LGotoPos(flayer, tx, W2D(ty));
1118 static void MarkAbort(void)
1120 int yend, redisp;
1122 markdata = (struct markdata *)flayer->l_data;
1123 fore = markdata->md_window;
1124 yend = fore->w_height - 1;
1125 redisp = markdata->second;
1126 if (fore->w_histheight - markdata->hist_offset < fore->w_height) {
1127 markdata->second = 0;
1128 yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
1130 if (markdata->hist_offset != fore->w_histheight) {
1131 LAY_CALL_UP(LRefreshAll(flayer, 0));
1132 } else {
1133 rem(markdata->x1, markdata->y1, markdata->cx, markdata->cy, redisp, NULL, yend);
1135 ExitOverlayPage();
1136 WindowChanged(fore, WINESC_COPY_MODE);
1139 static void MarkRedisplayLine(int y, int xs, int xe, int isblank)
1140 /* NOTE: y is in DISPLAY coords system! */
1142 int wy, x, i, rm;
1143 int sta, sto, cp; /* NOTE: these 3 are in WINDOW coords system */
1144 uint32_t *wi;
1145 struct mline *ml;
1146 struct mchar mchar_marked;
1148 if (y < 0) /* No special full page handling */
1149 return;
1151 markdata = (struct markdata *)flayer->l_data;
1152 fore = markdata->md_window;
1154 mchar_marked = mchar_so;
1156 wy = D2W(y);
1157 ml = WIN(wy);
1159 if (markdata->second == 0) {
1160 if (dw_right(ml, xs, fore->w_encoding) && xs > 0)
1161 xs--;
1162 if (dw_left(ml, xe, fore->w_encoding) && xe < fore->w_width - 1)
1163 xe++;
1164 if (xs == 0 && y > 0 && wy > 0 && WIN(wy - 1)->image[flayer->l_width] == 0)
1165 LCDisplayLineWrap(flayer, ml, y, xs, xe, isblank);
1166 else
1167 LCDisplayLine(flayer, ml, y, xs, xe, isblank);
1168 return;
1171 sta = markdata->y1 * fore->w_width + markdata->x1;
1172 sto = markdata->cy * fore->w_width + markdata->cx;
1173 if (sta > sto) {
1174 i = sta;
1175 sta = sto;
1176 sto = i;
1178 cp = wy * fore->w_width + xs;
1180 rm = markdata->right_mar;
1181 for (x = fore->w_width, wi = ml->image + fore->w_width; x >= 0; x--, wi--)
1182 if (*wi != ' ')
1183 break;
1184 if (x < rm)
1185 rm = x;
1187 for (x = xs; x <= xe; x++, cp++)
1188 if (cp >= sta && x >= markdata->left_mar)
1189 break;
1190 if (dw_right(ml, x, fore->w_encoding))
1191 x--;
1192 if (x > xs)
1193 LCDisplayLine(flayer, ml, y, xs, x - 1, isblank);
1194 for (; x <= xe; x++, cp++) {
1195 if (cp > sto || x > rm)
1196 break;
1197 if (pastefont) {
1198 mchar_marked.font = ml->font[x];
1200 mchar_marked.image = ml->image[x];
1201 mchar_marked.mbcs = 0;
1202 if (dw_left(ml, x, fore->w_encoding)) {
1203 mchar_marked.mbcs = ml->image[x + 1];
1204 cp++;
1206 LPutChar(flayer, &mchar_marked, x, y);
1207 if (dw_left(ml, x, fore->w_encoding))
1208 x++;
1210 if (x <= xe)
1211 LCDisplayLine(flayer, ml, y, x, xe, isblank);
1215 * scroll the screen contents up/down.
1217 static int MarkScrollUpDisplay(int n)
1219 int i;
1221 if (n <= 0)
1222 return 0;
1223 if (n > fore->w_histheight - markdata->hist_offset)
1224 n = fore->w_histheight - markdata->hist_offset;
1225 markdata->hist_offset += n;
1226 i = (n < flayer->l_height) ? n : (flayer->l_height);
1227 LScrollV(flayer, i, 0, flayer->l_height - 1, 0);
1228 while (i-- > 0)
1229 MarkRedisplayLine(flayer->l_height - i - 1, 0, flayer->l_width - 1, 1);
1230 return n;
1233 static int MarkScrollDownDisplay(int n)
1235 int i;
1237 if (n <= 0)
1238 return 0;
1239 if (n > markdata->hist_offset)
1240 n = markdata->hist_offset;
1241 markdata->hist_offset -= n;
1242 i = (n < flayer->l_height) ? n : (flayer->l_height);
1243 LScrollV(flayer, -i, 0, fore->w_height - 1, 0);
1244 while (i-- > 0)
1245 MarkRedisplayLine(i, 0, flayer->l_width - 1, 1);
1246 return n;
1249 void MakePaster(struct paster *pa, char *buf, size_t len, int bufiscopy)
1251 FreePaster(pa);
1252 pa->pa_pasteptr = buf;
1253 pa->pa_pastelen = len;
1254 if (bufiscopy)
1255 pa->pa_pastebuf = buf;
1256 pa->pa_pastelayer = flayer;
1257 DoProcess(Layer2Window(flayer), &pa->pa_pasteptr, &pa->pa_pastelen, pa);
1260 void FreePaster(struct paster *pa)
1262 if (pa->pa_pastebuf)
1263 free(pa->pa_pastebuf);
1264 pa->pa_pastebuf = NULL;
1265 pa->pa_pasteptr = NULL;
1266 pa->pa_pastelen = 0;
1267 pa->pa_pastelayer = NULL;
1268 evdeq(&pa->pa_slowev);