Remove screen.info from tracking.
[screen-lua.git] / src / mark.c
blob54c39f459718054429e616ccff186727bb4f3cb8
1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 ****************************************************************
24 #include <sys/types.h>
26 #include "config.h"
27 #include "screen.h"
28 #include "mark.h"
29 #include "extern.h"
31 #ifdef COPY_PASTE
34 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
36 * WARNING: these routines use the global variables "fore" and
37 * "flayer" to make things easier.
39 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
42 static int is_letter __P((int));
43 static void nextword __P((int *, int *, int, int));
44 static int linestart __P((int));
45 static int lineend __P((int));
46 static int rem __P((int, int , int , int , int , char *, int));
47 static int eq __P((int, int ));
48 static int MarkScrollDownDisplay __P((int));
49 static int MarkScrollUpDisplay __P((int));
51 static void MarkProcess __P((char **, int *));
52 static void MarkAbort __P((void));
53 static void MarkRedisplayLine __P((int, int, int, int));
54 static int MarkRewrite __P((int, int, int, struct mchar *, int));
56 extern struct layer *flayer;
57 extern struct display *display, *displays;
58 extern struct win *fore;
59 extern struct mline mline_blank, mline_null;
60 extern struct mchar mchar_so;
62 #ifdef FONT
63 int pastefont = 1;
64 #endif
66 struct LayFuncs MarkLf =
68 MarkProcess,
69 MarkAbort,
70 MarkRedisplayLine,
71 DefClearLine,
72 MarkRewrite,
73 DefResize,
74 DefRestore
77 int join_with_cr = 0;
78 int compacthist = 0;
80 unsigned char mark_key_tab[256]; /* this array must be initialised first! */
82 static struct markdata *markdata;
86 * VI like is_letter: 0 - whitespace
87 * 1 - letter
88 * 2 - other
90 static int is_letter(c)
91 char c;
93 if ((c >= 'a' && c <= 'z') ||
94 (c >= 'A' && c <= 'Z') ||
95 (c >= '0' && c <= '9') ||
96 c == '_' || c == '.' ||
97 c == '@' || c == ':' ||
98 c == '%' || c == '!' ||
99 c == '-' || c == '+')
100 /* thus we can catch email-addresses as a word :-) */
101 return 1;
102 else if (c != ' ')
103 return 2;
104 return 0;
107 static int
108 linestart(y)
109 int y;
111 register int x;
112 register unsigned char *i;
114 for (x = markdata->left_mar, i = WIN(y)->image + x; x < fore->w_width - 1; x++)
115 if (*i++ != ' ')
116 break;
117 if (x == fore->w_width - 1)
118 x = markdata->left_mar;
119 return x;
122 static int
123 lineend(y)
124 int y;
126 register int x;
127 register unsigned char *i;
129 for (x = markdata->right_mar, i = WIN(y)->image + x; x >= 0; x--)
130 if (*i-- != ' ')
131 break;
132 if (x < 0)
133 x = markdata->left_mar;
134 return x;
138 * nextchar sets *xp to the num-th occurrence of the target in the line.
140 * Returns -1 if the target doesn't appear num times, 0 otherwise.
142 static int
143 nextchar(int *xp, int *yp, int direction, char target, int num)
145 int width; /* width of the current window. */
146 int x; /* x coordinate of the current cursor position. */
147 int step; /* amount to increment x (+1 or -1) */
148 int adjust; /* Final adjustment of cursor position. */
149 char *displayed_line; /* Line in which search takes place. */
151 debug("nextchar\n");
153 x = *xp;
154 adjust = 0;
155 width = fore->w_width;
156 displayed_line = WIN(*yp) -> image;
158 switch(direction) {
159 case 't': adjust = -1; /* fall through */
160 case 'f': step = 1; /* fall through */
161 break;
162 case 'T': adjust = 1; /* fall through */
163 case 'F': step = -1; /* fall through */
164 break;
165 default:
166 ASSERT(0);
169 x += step;
171 debug1("ml->image = %s\n", displayed_line);
172 debug2("num = %d, width = %d\n",num, width);
173 debug2("x = %d target = %c\n", x, target );
175 for ( ;x>=0 && x <= width; x += step) {
176 if (displayed_line[x] == target) {
177 if (--num == 0) {
178 *xp = x + adjust;
179 return 0;
183 return -1;
187 * nextword calculates the cursor position of the num'th word.
188 * If the cursor is on a word, it counts as the first.
189 * NW_BACK: search backward
190 * NW_ENDOFWORD: find the end of the word
191 * NW_MUSTMOVE: move at least one char
192 * NW_BIG: match WORDs not words
195 #define NW_BACK (1<<0)
196 #define NW_ENDOFWORD (1<<1)
197 #define NW_MUSTMOVE (1<<2)
198 #define NW_BIG (1<<3)
202 static void
203 nextword(xp, yp, flags, num)
204 int *xp, *yp, flags, num;
206 int xx = fore->w_width, yy = fore->w_histheight + fore->w_height;
207 register int sx, oq, q, x, y;
208 struct mline *ml;
210 x = *xp;
211 y = *yp;
212 sx = (flags & NW_BACK) ? -1 : 1;
213 if ((flags & NW_ENDOFWORD) && (flags & NW_MUSTMOVE))
214 x += sx;
215 ml = WIN(y);
216 for (oq = -1; ; x += sx, oq = q)
218 if (x >= xx || x < 0)
219 q = 0;
220 else if (flags & NW_BIG)
221 q = ml->image[x] == ' ';
222 else
223 q = is_letter(ml->image[x]);
224 if (oq >= 0 && oq != q)
226 if (oq == 0 || !(flags & NW_ENDOFWORD))
227 *xp = x;
228 else
229 *xp = x-sx;
230 *yp = y;
231 if ((!(flags & NW_ENDOFWORD) && q) ||
232 ((flags & NW_ENDOFWORD) && oq))
234 if (--num <= 0)
235 return;
238 if (x == xx)
240 x = -1;
241 if (++y >= yy)
242 return;
243 ml = WIN(y);
245 else if (x < 0)
247 x = xx;
248 if (--y < 0)
249 return;
250 ml = WIN(y);
257 * y1, y2 are WIN coordinates
259 * redisplay: 0 - just copy
260 * 1 - redisplay + copy
261 * 2 - count + copy, don't redisplay
264 static int
265 rem(x1, y1, x2, y2, redisplay, pt, yend)
266 int x1, y1, x2, y2, redisplay, yend;
267 char *pt;
269 int i, j, from, to, ry, c;
270 int l = 0;
271 unsigned char *im;
272 struct mline *ml;
273 #ifdef FONT
274 int cf, font;
275 unsigned char *fo;
276 #endif
278 markdata->second = 0;
279 if (y2 < y1 || ((y2 == y1) && (x2 < x1)))
281 i = y2;
282 y2 = y1;
283 y1 = i;
284 i = x2;
285 x2 = x1;
286 x1 = i;
288 ry = y1 - markdata->hist_offset;
290 i = y1;
291 if (redisplay != 2 && pt == 0 && ry <0)
293 i -= ry;
294 ry = 0;
296 for (; i <= y2; i++, ry++)
298 if (redisplay != 2 && pt == 0 && ry > yend)
299 break;
300 ml = WIN(i);
301 from = (i == y1) ? x1 : 0;
302 if (from < markdata->left_mar)
303 from = markdata->left_mar;
304 for (to = fore->w_width, im = ml->image + to; to >= 0; to--)
305 if (*im-- != ' ')
306 break;
307 if (i == y2 && x2 < to)
308 to = x2;
309 if (to > markdata->right_mar)
310 to = markdata->right_mar;
311 if (redisplay == 1 && from <= to && ry >=0 && ry <= yend)
312 MarkRedisplayLine(ry, from, to, 0);
313 if (redisplay != 2 && pt == 0) /* don't count/copy */
314 continue;
315 j = from;
316 #ifdef DW_CHARS
317 if (dw_right(ml, j, fore->w_encoding))
318 j--;
319 #endif
320 im = ml->image + j;
321 #ifdef FONT
322 fo = ml->font + j;
323 font = ASCII;
324 #endif
325 for (; j <= to; j++)
327 c = (unsigned char)*im++;
328 #ifdef FONT
329 cf = (unsigned char)*fo++;
330 # ifdef UTF8
331 if (fore->w_encoding == UTF8)
333 c |= cf << 8;
334 if (c == UCS_HIDDEN)
335 continue;
336 c = ToUtf8_comb(pt, c);
337 l += c;
338 if (pt)
339 pt += c;
340 continue;
342 # endif
343 # ifdef DW_CHARS
344 if (is_dw_font(cf))
346 c = c << 8 | (unsigned char)*im++;
347 fo++;
348 j++;
350 # endif
351 if (pastefont)
353 c = EncodeChar(pt, c | cf << 16, fore->w_encoding, &font);
354 l += c;
355 if (pt)
356 pt += c;
357 continue;
359 #endif /* FONT */
360 if (pt)
361 *pt++ = c;
362 l++;
364 #ifdef FONT
365 if (pastefont && font != ASCII)
367 if (pt)
369 strcpy(pt, "\033(B");
370 pt += 3;
372 l += 3;
374 #endif
375 if (i != y2 && (to != fore->w_width - 1 || ml->image[to + 1] == ' '))
378 * this code defines, what glues lines together
380 switch (markdata->nonl)
382 case 0: /* lines separated by newlines */
383 if (pt)
384 *pt++ = '\r';
385 l++;
386 if (join_with_cr)
388 if (pt)
389 *pt++ = '\n';
390 l++;
392 break;
393 case 1: /* nothing to separate lines */
394 break;
395 case 2: /* lines separated by blanks */
396 if (pt)
397 *pt++ = ' ';
398 l++;
399 break;
400 case 3: /* seperate by comma, for csh junkies */
401 if (pt)
402 *pt++ = ',';
403 l++;
404 break;
408 return l;
411 /* Check if two chars are identical. All digits are treated
412 * as same. Used for GetHistory()
415 static int
416 eq(a, b)
417 int a, b;
419 if (a == b)
420 return 1;
421 if (a == 0 || b == 0)
422 return 1;
423 if (a <= '9' && a >= '0' && b <= '9' && b >= '0')
424 return 1;
425 return 0;
429 /**********************************************************************/
432 GetHistory() /* return value 1 if copybuffer changed */
434 int i = 0, q = 0, xx, yy, x, y;
435 unsigned char *linep;
436 struct mline *ml;
438 ASSERT(display && fore);
439 x = fore->w_x;
440 if (x >= fore->w_width)
441 x = fore->w_width - 1;
442 y = fore->w_y + fore->w_histheight;
443 debug2("cursor is at x=%d, y=%d\n", x, y);
444 ml = WIN(y);
445 for (xx = x - 1, linep = ml->image + xx; xx >= 0; xx--)
446 if ((q = *linep--) != ' ' )
447 break;
448 debug3("%c at (%d,%d)\n", q, xx, y);
449 for (yy = y - 1; yy >= 0; yy--)
451 ml = WIN(yy);
452 linep = ml->image;
453 if (xx < 0 || eq(linep[xx], q))
454 { /* line is matching... */
455 for (i = fore->w_width - 1, linep += i; i >= x; i--)
456 if (*linep-- != ' ')
457 break;
458 if (i >= x)
459 break;
462 if (yy < 0)
463 return 0;
464 if (D_user->u_plop.buf)
465 UserFreeCopyBuffer(D_user);
466 if ((D_user->u_plop.buf = (char *)malloc((unsigned) (i - x + 2))) == NULL)
468 LMsg(0, "Not enough memory... Sorry.");
469 return 0;
471 bcopy((char *)linep - i + x + 1, D_user->u_plop.buf, i - x + 1);
472 D_user->u_plop.len = i - x + 1;
473 #ifdef ENCODINGS
474 D_user->u_plop.enc = fore->w_encoding;
475 #endif
476 return 1;
479 /**********************************************************************/
482 void
483 MarkRoutine()
485 int x, y;
487 ASSERT(fore && display && D_user);
489 debug2("MarkRoutine called: fore nr %d, display %s\n",
490 fore->w_number, D_usertty);
492 if (InitOverlayPage(sizeof(*markdata), &MarkLf, 1))
493 return;
494 flayer->l_encoding = fore->w_encoding;
495 markdata = (struct markdata *)flayer->l_data;
496 markdata->md_user = D_user; /* XXX: Correct? */
497 markdata->md_window = fore;
498 markdata->second = 0;
499 markdata->rep_cnt = 0;
500 markdata->append_mode = 0;
501 markdata->write_buffer = 0;
502 markdata->nonl = 0;
503 markdata->left_mar = 0;
504 markdata->right_mar = fore->w_width - 1;
505 markdata->hist_offset = fore->w_histheight;
506 x = fore->w_x;
507 y = D2W(fore->w_y);
508 if (x >= fore->w_width)
509 x = fore->w_width - 1;
511 LGotoPos(flayer, x, W2D(y));
512 LMsg(0, "Copy mode - Column %d Line %d(+%d) (%d,%d)",
513 x + 1, W2D(y + 1), fore->w_histheight, fore->w_width, fore->w_height);
514 markdata->cx = markdata->x1 = x;
515 markdata->cy = markdata->y1 = y;
516 flayer->l_x = x;
517 flayer->l_y = W2D(y);
520 static void
521 MarkProcess(inbufp,inlenp)
522 char **inbufp;
523 int *inlenp;
525 char *inbuf, *pt;
526 int inlen;
527 int cx, cy, x2, y2, j, yend;
528 int newcopylen = 0, od;
529 int in_mark;
530 int rep_cnt;
531 struct acluser *md_user;
534 char *extrap = 0, extrabuf[100];
537 markdata = (struct markdata *)flayer->l_data;
538 fore = markdata->md_window;
539 md_user = markdata->md_user;
540 if (inbufp == 0)
542 MarkAbort();
543 return;
546 LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
547 inbuf= *inbufp;
548 inlen= *inlenp;
549 pt = inbuf;
550 in_mark = 1;
551 while (in_mark && (inlen /* || extrap */))
554 if (extrap)
556 od = *extrap++;
557 if (*extrap == 0)
558 extrap = 0;
560 else
563 od = mark_key_tab[(int)(unsigned char)*pt++];
564 inlen--;
566 rep_cnt = markdata->rep_cnt;
567 if (od >= '0' && od <= '9' && !markdata->f_cmd.flag)
569 if (rep_cnt < 1001 && (od != '0' || rep_cnt != 0))
571 markdata->rep_cnt = 10 * rep_cnt + od - '0';
572 continue;
574 * Now what is that 1001 here? Well, we have a screen with
575 * 25 * 80 = 2000 characters. Movement is at most across the full
576 * screen. This we do with word by word movement, as character by
577 * character movement never steps over line boundaries. The most words
578 * we can place on the screen are 1000 single letter words. Thus 1001
579 * is sufficient. Users with bigger screens never write in single letter
580 * words, as they should be more advanced. jw.
581 * Oh, wrong. We still give even the experienced user a factor of ten.
585 cx = markdata->cx;
586 cy = markdata->cy;
588 if (markdata -> f_cmd.flag) {
589 debug2("searching for %c:%d\n",od,rep_cnt);
590 markdata->f_cmd.flag = 0;
591 markdata->rep_cnt = 0;
593 if (isgraph (od)) {
594 markdata->f_cmd.target = od;
595 rep_cnt = (rep_cnt) ? rep_cnt : 1;
596 nextchar(&cx, &cy, markdata->f_cmd.direction, od, rep_cnt );
597 revto(cx, cy);
598 continue;
602 switch (od)
604 case 'f': /* fall through */
605 case 'F': /* fall through */
606 case 't': /* fall through */
607 case 'T': /* fall through */
609 * Set f_cmd to do a search on the next key stroke.
610 * If we break, rep_cnt will be reset, so we
611 * continue instead. It might be cleaner to
612 * store the rep_count in f_cmd and
613 * break here so later followon code will be
614 * hit.
616 markdata->f_cmd.flag = 1;
617 markdata->f_cmd.direction = od;
618 debug("entering char search\n");
619 continue;
620 case ';':
621 if (!markdata->f_cmd.target)
622 break;
623 if (!rep_cnt)
624 rep_cnt = 1;
625 nextchar(&cx, &cy, markdata->f_cmd.direction, markdata->f_cmd.target, rep_cnt );
626 revto(cx, cy);
627 break;
628 case ',': {
629 int search_dir;
630 if (!markdata->f_cmd.target)
631 break;
632 if (!rep_cnt)
633 rep_cnt = 1;
634 switch (markdata->f_cmd.direction) {
635 case 't': search_dir = 'T'; break;
636 case 'T': search_dir = 't'; break;
637 case 'f': search_dir = 'F'; break;
638 case 'F': search_dir = 'f'; break;
640 nextchar(&cx, &cy, search_dir, markdata->f_cmd.target, rep_cnt );
641 revto(cx, cy);
642 break;
645 case 'o':
646 case 'x':
647 if (!markdata->second)
648 break;
649 markdata->cx = markdata->x1;
650 markdata->cy = markdata->y1;
651 markdata->x1 = cx;
652 markdata->y1 = cy;
653 revto(markdata->cx, markdata->cy);
654 break;
655 case '\014': /* CTRL-L Redisplay */
656 Redisplay(0);
657 LGotoPos(flayer, cx, W2D(cy));
658 break;
659 case 0202: /* M-C-b */
660 case '\010': /* CTRL-H Backspace */
661 case 'h':
662 if (rep_cnt == 0)
663 rep_cnt = 1;
664 revto(cx - rep_cnt, cy);
665 break;
666 case 0216: /* M-C-p */
667 case '\016': /* CTRL-N */
668 case 'j':
669 if (rep_cnt == 0)
670 rep_cnt = 1;
671 revto(cx, cy + rep_cnt);
672 break;
673 case '+':
674 if (rep_cnt == 0)
675 rep_cnt = 1;
676 j = cy + rep_cnt;
677 if (j > fore->w_histheight + fore->w_height - 1)
678 j = fore->w_histheight + fore->w_height - 1;
679 revto(linestart(j), j);
680 break;
681 case '-':
682 if (rep_cnt == 0)
683 rep_cnt = 1;
684 cy -= rep_cnt;
685 if (cy < 0)
686 cy = 0;
687 revto(linestart(cy), cy);
688 break;
689 case '^':
690 revto(linestart(cy), cy);
691 break;
692 case '\n':
693 revto(markdata->left_mar, cy + 1);
694 break;
695 case 0220: /* M-C-p */
696 case '\020': /* CTRL-P */
697 case 'k':
698 if (rep_cnt == 0)
699 rep_cnt = 1;
700 revto(cx, cy - rep_cnt);
701 break;
702 case 0206: /* M-C-f */
703 case 'l':
704 if (rep_cnt == 0)
705 rep_cnt = 1;
706 revto(cx + rep_cnt, cy);
707 break;
708 case '\001': /* CTRL-A from tcsh/emacs */
709 case '0':
710 revto(markdata->left_mar, cy);
711 break;
712 case '\004': /* CTRL-D down half screen */
713 if (rep_cnt == 0)
714 rep_cnt = (fore->w_height + 1) >> 1;
715 revto_line(cx, cy + rep_cnt, W2D(cy));
716 break;
717 case '$':
718 revto(lineend(cy), cy);
719 break;
720 case '\022': /* CTRL-R emacs style backwards search */
721 ISearch(-1);
722 in_mark = 0;
723 break;
724 case '\023': /* CTRL-S emacs style search */
725 ISearch(1);
726 in_mark = 0;
727 break;
728 case '\025': /* CTRL-U up half screen */
729 if (rep_cnt == 0)
730 rep_cnt = (fore->w_height + 1) >> 1;
731 revto_line(cx, cy - rep_cnt, W2D(cy));
732 break;
733 case '\007': /* CTRL-G show cursorpos */
734 if (markdata->left_mar == 0 && markdata->right_mar == fore->w_width - 1)
735 LMsg(0, "Column %d Line %d(+%d)", cx+1, W2D(cy)+1,
736 markdata->hist_offset);
737 else
738 LMsg(0, "Column %d(%d..%d) Line %d(+%d)", cx+1,
739 markdata->left_mar+1, markdata->right_mar+1, W2D(cy)+1, markdata->hist_offset);
740 break;
741 case '\002': /* CTRL-B back one page */
742 if (rep_cnt == 0)
743 rep_cnt = 1;
744 rep_cnt *= fore->w_height;
745 revto(cx, cy - rep_cnt);
746 break;
747 case '\006': /* CTRL-F forward one page */
748 if (rep_cnt == 0)
749 rep_cnt = 1;
750 rep_cnt *= fore->w_height;
751 revto(cx, cy + rep_cnt);
752 break;
753 case '\005': /* CTRL-E scroll up */
754 if (rep_cnt == 0)
755 rep_cnt = 1;
756 rep_cnt = MarkScrollUpDisplay(rep_cnt);
757 if (cy < D2W(0))
758 revto(cx, D2W(0));
759 else
760 LGotoPos(flayer, cx, W2D(cy));
761 break;
762 case '\031': /* CTRL-Y scroll down */
763 if (rep_cnt == 0)
764 rep_cnt = 1;
765 rep_cnt = MarkScrollDownDisplay(rep_cnt);
766 if (cy > D2W(fore->w_height-1))
767 revto(cx, D2W(fore->w_height-1));
768 else
769 LGotoPos(flayer, cx, W2D(cy));
770 break;
771 case '@':
772 /* it may be usefull to have a key that does nothing */
773 break;
774 case '%':
775 rep_cnt--;
776 /* rep_cnt is a percentage for the history buffer */
777 if (rep_cnt < 0)
778 rep_cnt = 0;
779 if (rep_cnt > 100)
780 rep_cnt = 100;
781 revto_line(markdata->left_mar, (rep_cnt * (fore->w_histheight + fore->w_height)) / 100, (fore->w_height - 1) / 2);
782 break;
783 case 0201:
784 case 'g':
785 rep_cnt = 1;
786 /* FALLTHROUGH */
787 case 0205:
788 case 'G':
789 /* rep_cnt is here the WIN line number */
790 if (rep_cnt == 0)
791 rep_cnt = fore->w_histheight + fore->w_height;
792 revto_line(markdata->left_mar, --rep_cnt, (fore->w_height - 1) / 2);
793 break;
794 case 'H':
795 revto(markdata->left_mar, D2W(0));
796 break;
797 case 'M':
798 revto(markdata->left_mar, D2W((fore->w_height - 1) / 2));
799 break;
800 case 'L':
801 revto(markdata->left_mar, D2W(fore->w_height - 1));
802 break;
803 case '|':
804 revto(--rep_cnt, cy);
805 break;
806 case 'w':
807 if (rep_cnt == 0)
808 rep_cnt = 1;
809 nextword(&cx, &cy, NW_MUSTMOVE, rep_cnt);
810 revto(cx, cy);
811 break;
812 case 'e':
813 case 'E':
814 if (rep_cnt == 0)
815 rep_cnt = 1;
816 nextword(&cx, &cy, NW_ENDOFWORD|NW_MUSTMOVE | (od == 'E' ? NW_BIG : 0), rep_cnt);
817 revto(cx, cy);
818 break;
819 case 'b':
820 case 'B':
821 if (rep_cnt == 0)
822 rep_cnt = 1;
823 nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD|NW_MUSTMOVE | (od == 'B' ? NW_BIG : 0), rep_cnt);
824 revto(cx, cy);
825 break;
826 case 'a':
827 markdata->append_mode = 1 - markdata->append_mode;
828 debug1("append mode %d--\n", markdata->append_mode);
829 LMsg(0, (markdata->append_mode) ? ":set append" : ":set noappend");
830 break;
831 case 'v':
832 case 'V':
833 /* this sets start column to column 9 for VI :set nu users */
834 if (markdata->left_mar == 8)
835 rep_cnt = 1;
836 else
837 rep_cnt = 9;
838 /* FALLTHROUGH */
839 case 'c':
840 case 'C':
841 /* set start column (c) and end column (C) */
842 if (markdata->second)
844 rem(markdata->x1, markdata->y1, cx, cy, 1, (char *)0, fore->w_height-1); /* Hack */
845 markdata->second = 1; /* rem turns off second */
847 rep_cnt--;
848 if (rep_cnt < 0)
849 rep_cnt = cx;
850 if (od != 'C')
852 markdata->left_mar = rep_cnt;
853 if (markdata->left_mar > markdata->right_mar)
854 markdata->left_mar = markdata->right_mar;
856 else
858 markdata->right_mar = rep_cnt;
859 if (markdata->left_mar > markdata->right_mar)
860 markdata->right_mar = markdata->left_mar;
862 if (markdata->second)
864 markdata->cx = markdata->x1; markdata->cy = markdata->y1;
865 revto(cx, cy);
867 if (od == 'v' || od == 'V')
868 LMsg(0, (markdata->left_mar != 8) ? ":set nonu" : ":set nu");
869 break;
870 case 'J':
871 /* how do you join lines in VI ? */
872 markdata->nonl = (markdata->nonl + 1) % 4;
873 switch (markdata->nonl)
875 case 0:
876 if (join_with_cr)
877 LMsg(0, "Multiple lines (CR/LF)");
878 else
879 LMsg(0, "Multiple lines (LF)");
880 break;
881 case 1:
882 LMsg(0, "Lines joined");
883 break;
884 case 2:
885 LMsg(0, "Lines joined with blanks");
886 break;
887 case 3:
888 LMsg(0, "Lines joined with comma");
889 break;
891 break;
892 case '/':
893 Search(1);
894 in_mark = 0;
895 break;
896 case '?':
897 Search(-1);
898 in_mark = 0;
899 break;
900 case 'n':
901 Search(0);
902 break;
903 case 'N':
904 markdata->isdir = -markdata->isdir;
905 Search(0);
906 markdata->isdir = -markdata->isdir;
907 break;
908 case 'y':
909 case 'Y':
910 if (markdata->second == 0)
912 revto(linestart(cy), cy);
913 markdata->second++;
914 cx = markdata->x1 = markdata->cx;
915 cy = markdata->y1 = markdata->cy;
917 if (--rep_cnt > 0)
918 revto(cx, cy + rep_cnt);
919 revto(lineend(markdata->cy), markdata->cy);
920 if (od == 'y')
921 break;
922 /* FALLTHROUGH */
923 case 'W':
924 if (od == 'W')
926 if (rep_cnt == 0)
927 rep_cnt = 1;
928 if (!markdata->second)
930 nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD, 1);
931 revto(cx, cy);
932 markdata->second++;
933 cx = markdata->x1 = markdata->cx;
934 cy = markdata->y1 = markdata->cy;
936 nextword(&cx, &cy, NW_ENDOFWORD, rep_cnt);
937 revto(cx, cy);
939 cx = markdata->cx;
940 cy = markdata->cy;
941 /* FALLTHROUGH */
942 case 'A':
943 if (od == 'A')
944 markdata->append_mode = 1;
945 /* FALLTHROUGH */
946 case '>':
947 if (od == '>')
948 markdata->write_buffer = 1;
949 /* FALLTHROUGH */
950 case ' ':
951 case '\r':
952 if (!markdata->second)
954 markdata->second++;
955 markdata->x1 = cx;
956 markdata->y1 = cy;
957 revto(cx, cy);
958 LMsg(0, "First mark set - Column %d Line %d", cx+1, W2D(cy)+1);
959 break;
961 else
963 int append_mode = markdata->append_mode;
964 int write_buffer = markdata->write_buffer;
966 x2 = cx;
967 y2 = cy;
968 newcopylen = rem(markdata->x1, markdata->y1, x2, y2, 2, (char *)0, 0); /* count */
969 if (md_user->u_plop.buf && !append_mode)
970 UserFreeCopyBuffer(md_user);
971 yend = fore->w_height - 1;
972 if (fore->w_histheight - markdata->hist_offset < fore->w_height)
974 markdata->second = 0;
975 yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
977 if (newcopylen > 0)
979 /* the +3 below is for : cr + lf + \0 */
980 if (md_user->u_plop.buf)
981 md_user->u_plop.buf = realloc(md_user->u_plop.buf,
982 (unsigned) (md_user->u_plop.len + newcopylen + 3));
983 else
985 md_user->u_plop.len = 0;
986 md_user->u_plop.buf = malloc((unsigned) (newcopylen + 3));
988 if (!md_user->u_plop.buf)
990 MarkAbort();
991 in_mark = 0;
992 LMsg(0, "Not enough memory... Sorry.");
993 md_user->u_plop.len = 0;
994 md_user->u_plop.buf = 0;
995 break;
997 if (append_mode)
999 switch (markdata->nonl)
1002 * this code defines, what glues lines together
1004 case 0:
1005 if (join_with_cr)
1007 md_user->u_plop.buf[md_user->u_plop.len] = '\r';
1008 md_user->u_plop.len++;
1010 md_user->u_plop.buf[md_user->u_plop.len] = '\n';
1011 md_user->u_plop.len++;
1012 break;
1013 case 1:
1014 break;
1015 case 2:
1016 md_user->u_plop.buf[md_user->u_plop.len] = ' ';
1017 md_user->u_plop.len++;
1018 break;
1019 case 3:
1020 md_user->u_plop.buf[md_user->u_plop.len] = ',';
1021 md_user->u_plop.len++;
1022 break;
1025 md_user->u_plop.len += rem(markdata->x1, markdata->y1, x2, y2,
1026 markdata->hist_offset == fore->w_histheight,
1027 md_user->u_plop.buf + md_user->u_plop.len, yend);
1028 #ifdef ENCODINGS
1029 md_user->u_plop.enc = fore->w_encoding;
1030 #endif
1032 if (markdata->hist_offset != fore->w_histheight)
1034 LAY_CALL_UP(LRefreshAll(flayer, 0));
1036 ExitOverlayPage();
1037 if (append_mode)
1038 LMsg(0, "Appended %d characters to buffer",
1039 newcopylen);
1040 else
1041 LMsg(0, "Copied %d characters into buffer", md_user->u_plop.len);
1042 if (write_buffer)
1043 WriteFile(md_user, (char *)0, DUMP_EXCHANGE);
1044 in_mark = 0;
1045 break;
1047 default:
1048 MarkAbort();
1049 LMsg(0, "Copy mode aborted");
1050 in_mark = 0;
1051 break;
1053 if (in_mark) /* markdata may be freed */
1054 markdata->rep_cnt = 0;
1056 if (in_mark)
1058 flayer->l_x = markdata->cx;
1059 flayer->l_y = W2D(markdata->cy);
1061 *inbufp = pt;
1062 *inlenp = inlen;
1065 void revto(tx, ty)
1066 int tx, ty;
1068 revto_line(tx, ty, -1);
1071 /* tx, ty: WINDOW, line: DISPLAY */
1072 void revto_line(tx, ty, line)
1073 int tx, ty, line;
1075 int fx, fy;
1076 int x, y, t, revst, reven, qq, ff, tt, st, en, ce = 0;
1077 int ystart = 0, yend = fore->w_height-1;
1078 int i, ry;
1079 unsigned char *wi;
1080 struct mline *ml;
1081 struct mchar mc;
1083 if (tx < 0)
1084 tx = 0;
1085 else if (tx > fore->w_width - 1)
1086 tx = fore->w_width -1;
1087 if (ty < 0)
1088 ty = 0;
1089 else if (ty > fore->w_histheight + fore->w_height - 1)
1090 ty = fore->w_histheight + fore->w_height - 1;
1092 fx = markdata->cx; fy = markdata->cy;
1094 #ifdef DW_CHARS
1095 /* don't just move inside of a kanji, the user wants to see something */
1096 ml = WIN(ty);
1097 if (ty == fy && fx + 1 == tx && dw_right(ml, tx, fore->w_encoding) && tx < D_width - 1)
1098 tx++;
1099 if (ty == fy && fx - 1 == tx && dw_right(ml, fx, fore->w_encoding) && tx)
1100 tx--;
1101 #endif
1103 markdata->cx = tx; markdata->cy = ty;
1106 * if we go to a position that is currently offscreen
1107 * then scroll the screen
1109 i = 0;
1110 if (line >= 0 && line < fore->w_height)
1111 i = W2D(ty) - line;
1112 else if (ty < markdata->hist_offset)
1113 i = ty - markdata->hist_offset;
1114 else if (ty > markdata->hist_offset + (fore->w_height - 1))
1115 i = ty - markdata->hist_offset - (fore->w_height - 1);
1116 if (i > 0)
1117 yend -= MarkScrollUpDisplay(i);
1118 else if (i < 0)
1119 ystart += MarkScrollDownDisplay(-i);
1121 if (markdata->second == 0)
1123 LGotoPos(flayer, tx, W2D(ty));
1124 return;
1127 qq = markdata->x1 + markdata->y1 * fore->w_width;
1128 ff = fx + fy * fore->w_width; /* "from" offset in WIN coords */
1129 tt = tx + ty * fore->w_width; /* "to" offset in WIN coords*/
1131 if (ff > tt)
1133 st = tt; en = ff;
1134 x = tx; y = ty;
1136 else
1138 st = ff; en = tt;
1139 x = fx; y = fy;
1141 if (st > qq)
1143 st++;
1144 x++;
1146 if (en < qq)
1147 en--;
1148 if (tt > qq)
1150 revst = qq; reven = tt;
1152 else
1154 revst = tt; reven = qq;
1156 ry = y - markdata->hist_offset;
1157 if (ry < ystart)
1159 y += (ystart - ry);
1160 x = 0;
1161 st = y * fore->w_width;
1162 ry = ystart;
1164 ml = WIN(y);
1165 for (t = st; t <= en; t++, x++)
1167 if (x >= fore->w_width)
1169 x = 0;
1170 y++, ry++;
1171 ml = WIN(y);
1173 if (ry > yend)
1174 break;
1175 if (t == st || x == 0)
1177 wi = ml->image + fore->w_width;
1178 for (ce = fore->w_width; ce >= 0; ce--, wi--)
1179 if (*wi != ' ')
1180 break;
1182 if (x <= ce && x >= markdata->left_mar && x <= markdata->right_mar)
1184 #ifdef DW_CHARS
1185 if (dw_right(ml, x, fore->w_encoding))
1187 if (t == revst)
1188 revst--;
1189 t--;
1190 x--;
1192 #endif
1193 if (t >= revst && t <= reven)
1195 mc = mchar_so;
1196 #ifdef FONT
1197 if (pastefont)
1198 mc.font = ml->font[x];
1199 #endif
1200 mc.image = ml->image[x];
1202 else
1203 copy_mline2mchar(&mc, ml, x);
1204 #ifdef DW_CHARS
1205 if (dw_left(ml, x, fore->w_encoding))
1207 mc.mbcs = ml->image[x + 1];
1208 LPutChar(flayer, &mc, x, W2D(y));
1209 t++;
1211 #endif
1212 LPutChar(flayer, &mc, x, W2D(y));
1213 #ifdef DW_CHARS
1214 if (dw_left(ml, x, fore->w_encoding))
1215 x++;
1216 #endif
1219 LGotoPos(flayer, tx, W2D(ty));
1222 static void
1223 MarkAbort()
1225 int yend, redisp;
1227 debug("MarkAbort\n");
1228 markdata = (struct markdata *)flayer->l_data;
1229 fore = markdata->md_window;
1230 yend = fore->w_height - 1;
1231 redisp = markdata->second;
1232 if (fore->w_histheight - markdata->hist_offset < fore->w_height)
1234 markdata->second = 0;
1235 yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
1237 if (markdata->hist_offset != fore->w_histheight)
1239 LAY_CALL_UP(LRefreshAll(flayer, 0));
1241 else
1243 rem(markdata->x1, markdata->y1, markdata->cx, markdata->cy, redisp, (char *)0, yend);
1245 ExitOverlayPage();
1249 static void
1250 MarkRedisplayLine(y, xs, xe, isblank)
1251 int y; /* NOTE: y is in DISPLAY coords system! */
1252 int xs, xe;
1253 int isblank;
1255 int wy, x, i, rm;
1256 int sta, sto, cp; /* NOTE: these 3 are in WINDOW coords system */
1257 unsigned char *wi;
1258 struct mline *ml;
1259 struct mchar mchar_marked;
1261 if (y < 0) /* No special full page handling */
1262 return;
1264 markdata = (struct markdata *)flayer->l_data;
1265 fore = markdata->md_window;
1267 mchar_marked = mchar_so;
1269 wy = D2W(y);
1270 ml = WIN(wy);
1272 if (markdata->second == 0)
1274 if (dw_right(ml, xs, fore->w_encoding) && xs > 0)
1275 xs--;
1276 if (dw_left(ml, xe, fore->w_encoding) && xe < fore->w_width - 1)
1277 xe++;
1278 if (xs == 0 && y > 0 && wy > 0 && WIN(wy - 1)->image[flayer->l_width] == 0)
1279 LCDisplayLineWrap(flayer, ml, y, xs, xe, isblank);
1280 else
1281 LCDisplayLine(flayer, ml, y, xs, xe, isblank);
1282 return;
1285 sta = markdata->y1 * fore->w_width + markdata->x1;
1286 sto = markdata->cy * fore->w_width + markdata->cx;
1287 if (sta > sto)
1289 i=sta; sta=sto; sto=i;
1291 cp = wy * fore->w_width + xs;
1293 rm = markdata->right_mar;
1294 for (x = fore->w_width, wi = ml->image + fore->w_width; x >= 0; x--, wi--)
1295 if (*wi != ' ')
1296 break;
1297 if (x < rm)
1298 rm = x;
1300 for (x = xs; x <= xe; x++, cp++)
1301 if (cp >= sta && x >= markdata->left_mar)
1302 break;
1303 #ifdef DW_CHARS
1304 if (dw_right(ml, x, fore->w_encoding))
1305 x--;
1306 #endif
1307 if (x > xs)
1308 LCDisplayLine(flayer, ml, y, xs, x - 1, isblank);
1309 for (; x <= xe; x++, cp++)
1311 if (cp > sto || x > rm)
1312 break;
1313 #ifdef FONT
1314 if (pastefont)
1315 mchar_marked.font = ml->font[x];
1316 #endif
1317 mchar_marked.image = ml->image[x];
1318 #ifdef DW_CHARS
1319 mchar_marked.mbcs = 0;
1320 if (dw_left(ml, x, fore->w_encoding))
1322 mchar_marked.mbcs = ml->image[x + 1];
1323 cp++;
1325 #endif
1326 LPutChar(flayer, &mchar_marked, x, y);
1327 #ifdef DW_CHARS
1328 if (dw_left(ml, x, fore->w_encoding))
1329 x++;
1330 #endif
1332 if (x <= xe)
1333 LCDisplayLine(flayer, ml, y, x, xe, isblank);
1338 * This ugly routine is to speed up GotoPos()
1340 static int
1341 MarkRewrite(ry, xs, xe, rend, doit)
1342 int ry, xs, xe, doit;
1343 struct mchar *rend;
1345 int dx, x, y, st, en, t, rm;
1346 unsigned char *i;
1347 struct mline *ml;
1348 struct mchar mchar_marked;
1350 mchar_marked = mchar_so;
1352 debug3("MarkRewrite %d, %d-%d\n", ry, xs, xe);
1353 markdata = (struct markdata *)flayer->l_data;
1354 fore = markdata->md_window;
1355 y = D2W(ry);
1356 ml = WIN(y);
1357 #ifdef UTF8
1358 if (fore->w_encoding && fore->w_encoding != UTF8 && D_encoding == UTF8 && ContainsSpecialDeffont(ml, xs, xe, fore->w_encoding))
1359 return EXPENSIVE;
1360 #endif
1361 dx = xe - xs + 1;
1362 if (doit)
1364 i = ml->image + xs;
1365 while (dx--)
1366 PUTCHAR(*i++);
1367 return 0;
1370 if (markdata->second == 0)
1371 st = en = -1;
1372 else
1374 st = markdata->y1 * fore->w_width + markdata->x1;
1375 en = markdata->cy * fore->w_width + markdata->cx;
1376 if (st > en)
1378 t = st; st = en; en = t;
1381 t = y * fore->w_width + xs;
1382 for (rm = fore->w_width, i = ml->image + fore->w_width; rm >= 0; rm--)
1383 if (*i-- != ' ')
1384 break;
1385 if (rm > markdata->right_mar)
1386 rm = markdata->right_mar;
1387 x = xs;
1388 while (dx--)
1390 if (t >= st && t <= en && x >= markdata->left_mar && x <= rm)
1392 #ifdef FONT
1393 if (pastefont)
1394 mchar_marked.font = ml->font[x];
1395 #endif
1396 rend->image = mchar_marked.image;
1397 if (!cmp_mchar(rend, &mchar_marked))
1398 return EXPENSIVE;
1400 else
1402 rend->image = ml->image[x];
1403 if (!cmp_mchar_mline(rend, ml, x))
1404 return EXPENSIVE;
1406 x++;
1408 return xe - xs + 1;
1413 * scroll the screen contents up/down.
1415 static int MarkScrollUpDisplay(n)
1416 int n;
1418 int i;
1420 debug1("MarkScrollUpDisplay(%d)\n", n);
1421 if (n <= 0)
1422 return 0;
1423 if (n > fore->w_histheight - markdata->hist_offset)
1424 n = fore->w_histheight - markdata->hist_offset;
1425 markdata->hist_offset += n;
1426 i = (n < flayer->l_height) ? n : (flayer->l_height);
1427 LScrollV(flayer, i, 0, flayer->l_height - 1, 0);
1428 while (i-- > 0)
1429 MarkRedisplayLine(flayer->l_height - i - 1, 0, flayer->l_width - 1, 1);
1430 return n;
1433 static int
1434 MarkScrollDownDisplay(n)
1435 int n;
1437 int i;
1439 debug1("MarkScrollDownDisplay(%d)\n", n);
1440 if (n <= 0)
1441 return 0;
1442 if (n > markdata->hist_offset)
1443 n = markdata->hist_offset;
1444 markdata->hist_offset -= n;
1445 i = (n < flayer->l_height) ? n : (flayer->l_height);
1446 LScrollV(flayer, -i, 0, fore->w_height - 1, 0);
1447 while (i-- > 0)
1448 MarkRedisplayLine(i, 0, flayer->l_width - 1, 1);
1449 return n;
1453 InMark()
1455 if (flayer && flayer->l_layfn == &MarkLf)
1456 return 1;
1457 return 0;
1460 void
1461 MakePaster(pa, buf, len, bufiscopy)
1462 struct paster *pa;
1463 char *buf;
1464 int len;
1465 int bufiscopy;
1467 FreePaster(pa);
1468 pa->pa_pasteptr = buf;
1469 pa->pa_pastelen = len;
1470 if (bufiscopy)
1471 pa->pa_pastebuf = buf;
1472 pa->pa_pastelayer = flayer;
1473 DoProcess(Layer2Window(flayer), &pa->pa_pasteptr, &pa->pa_pastelen, pa);
1476 void
1477 FreePaster(pa)
1478 struct paster *pa;
1480 if (pa->pa_pastebuf)
1481 free(pa->pa_pastebuf);
1482 pa->pa_pastebuf = 0;
1483 pa->pa_pasteptr = 0;
1484 pa->pa_pastelen = 0;
1485 pa->pa_pastelayer = 0;
1486 evdeq(&pa->pa_slowev);
1489 #endif /* COPY_PASTE */