Fix some more windowlist glitches
[screen-lua.git] / src / mark.c
blob2598bdea484496b73f41bfcb727ffeda4d366147
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>
25 #include <ctype.h>
27 #include "config.h"
28 #include "screen.h"
29 #include "mark.h"
30 #include "extern.h"
32 #ifdef COPY_PASTE
35 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
37 * WARNING: these routines use the global variables "fore" and
38 * "flayer" to make things easier.
40 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
43 static int is_letter __P((int));
44 static void nextword __P((int *, int *, int, int));
45 static int linestart __P((int));
46 static int lineend __P((int));
47 static int rem __P((int, int , int , int , int , char *, int));
48 static int eq __P((int, int ));
49 static int MarkScrollDownDisplay __P((int));
50 static int MarkScrollUpDisplay __P((int));
52 static void MarkProcess __P((char **, int *));
53 static void MarkAbort __P((void));
54 static void MarkRedisplayLine __P((int, int, int, int));
55 static int MarkRewrite __P((int, int, int, struct mchar *, int));
57 extern struct layer *flayer;
58 extern struct display *display, *displays;
59 extern struct win *fore;
60 extern struct mline mline_blank, mline_null;
61 extern struct mchar mchar_so;
63 #ifdef FONT
64 int pastefont = 1;
65 #endif
67 struct LayFuncs MarkLf =
69 MarkProcess,
70 MarkAbort,
71 MarkRedisplayLine,
72 DefClearLine,
73 MarkRewrite,
74 DefResize,
75 DefRestore
78 int join_with_cr = 0;
79 int compacthist = 0;
81 unsigned char mark_key_tab[256]; /* this array must be initialised first! */
83 static struct markdata *markdata;
87 * VI like is_letter: 0 - whitespace
88 * 1 - letter
89 * 2 - other
91 static int is_letter(c)
92 char c;
94 if ((c >= 'a' && c <= 'z') ||
95 (c >= 'A' && c <= 'Z') ||
96 (c >= '0' && c <= '9') ||
97 c == '_' || c == '.' ||
98 c == '@' || c == ':' ||
99 c == '%' || c == '!' ||
100 c == '-' || c == '+')
101 /* thus we can catch email-addresses as a word :-) */
102 return 1;
103 else if (c != ' ')
104 return 2;
105 return 0;
108 static int
109 linestart(y)
110 int y;
112 register int x;
113 register unsigned char *i;
115 for (x = markdata->left_mar, i = WIN(y)->image + x; x < fore->w_width - 1; x++)
116 if (*i++ != ' ')
117 break;
118 if (x == fore->w_width - 1)
119 x = markdata->left_mar;
120 return x;
123 static int
124 lineend(y)
125 int y;
127 register int x;
128 register unsigned char *i;
130 for (x = markdata->right_mar, i = WIN(y)->image + x; x >= 0; x--)
131 if (*i-- != ' ')
132 break;
133 if (x < 0)
134 x = markdata->left_mar;
135 return x;
139 * nextchar sets *xp to the num-th occurrence of the target in the line.
141 * Returns -1 if the target doesn't appear num times, 0 otherwise.
143 static int
144 nextchar(int *xp, int *yp, int direction, char target, int num)
146 int width; /* width of the current window. */
147 int x; /* x coordinate of the current cursor position. */
148 int step; /* amount to increment x (+1 or -1) */
149 int adjust; /* Final adjustment of cursor position. */
150 char *displayed_line; /* Line in which search takes place. */
152 debug("nextchar\n");
154 x = *xp;
155 adjust = 0;
156 width = fore->w_width;
157 displayed_line = (char *)WIN(*yp) -> image;
159 switch(direction) {
160 case 't': adjust = -1; /* fall through */
161 case 'f': step = 1; /* fall through */
162 break;
163 case 'T': adjust = 1; /* fall through */
164 case 'F': step = -1; /* fall through */
165 break;
166 default:
167 ASSERT(0);
170 x += step;
172 debug1("ml->image = %s\n", displayed_line);
173 debug2("num = %d, width = %d\n",num, width);
174 debug2("x = %d target = %c\n", x, target );
176 for ( ;x>=0 && x <= width; x += step) {
177 if (displayed_line[x] == target) {
178 if (--num == 0) {
179 *xp = x + adjust;
180 return 0;
184 return -1;
188 * nextword calculates the cursor position of the num'th word.
189 * If the cursor is on a word, it counts as the first.
190 * NW_BACK: search backward
191 * NW_ENDOFWORD: find the end of the word
192 * NW_MUSTMOVE: move at least one char
193 * NW_BIG: match WORDs not words
196 #define NW_BACK (1<<0)
197 #define NW_ENDOFWORD (1<<1)
198 #define NW_MUSTMOVE (1<<2)
199 #define NW_BIG (1<<3)
203 static void
204 nextword(xp, yp, flags, num)
205 int *xp, *yp, flags, num;
207 int xx = fore->w_width, yy = fore->w_histheight + fore->w_height;
208 register int sx, oq, q, x, y;
209 struct mline *ml;
211 x = *xp;
212 y = *yp;
213 sx = (flags & NW_BACK) ? -1 : 1;
214 if ((flags & NW_ENDOFWORD) && (flags & NW_MUSTMOVE))
215 x += sx;
216 ml = WIN(y);
217 for (oq = -1; ; x += sx, oq = q)
219 if (x >= xx || x < 0)
220 q = 0;
221 else if (flags & NW_BIG)
222 q = ml->image[x] == ' ';
223 else
224 q = is_letter(ml->image[x]);
225 if (oq >= 0 && oq != q)
227 if (oq == 0 || !(flags & NW_ENDOFWORD))
228 *xp = x;
229 else
230 *xp = x-sx;
231 *yp = y;
232 if ((!(flags & NW_ENDOFWORD) && q) ||
233 ((flags & NW_ENDOFWORD) && oq))
235 if (--num <= 0)
236 return;
239 if (x == xx)
241 x = -1;
242 if (++y >= yy)
243 return;
244 ml = WIN(y);
246 else if (x < 0)
248 x = xx;
249 if (--y < 0)
250 return;
251 ml = WIN(y);
258 * y1, y2 are WIN coordinates
260 * redisplay: 0 - just copy
261 * 1 - redisplay + copy
262 * 2 - count + copy, don't redisplay
265 static int
266 rem(x1, y1, x2, y2, redisplay, pt, yend)
267 int x1, y1, x2, y2, redisplay, yend;
268 char *pt;
270 int i, j, from, to, ry, c;
271 int l = 0;
272 unsigned char *im;
273 struct mline *ml;
274 #ifdef FONT
275 int cf, font;
276 unsigned char *fo;
277 #endif
279 markdata->second = 0;
280 if (y2 < y1 || ((y2 == y1) && (x2 < x1)))
282 i = y2;
283 y2 = y1;
284 y1 = i;
285 i = x2;
286 x2 = x1;
287 x1 = i;
289 ry = y1 - markdata->hist_offset;
291 i = y1;
292 if (redisplay != 2 && pt == 0 && ry <0)
294 i -= ry;
295 ry = 0;
297 for (; i <= y2; i++, ry++)
299 if (redisplay != 2 && pt == 0 && ry > yend)
300 break;
301 ml = WIN(i);
302 from = (i == y1) ? x1 : 0;
303 if (from < markdata->left_mar)
304 from = markdata->left_mar;
305 for (to = fore->w_width, im = ml->image + to; to >= 0; to--)
306 if (*im-- != ' ')
307 break;
308 if (i == y2 && x2 < to)
309 to = x2;
310 if (to > markdata->right_mar)
311 to = markdata->right_mar;
312 if (redisplay == 1 && from <= to && ry >=0 && ry <= yend)
313 MarkRedisplayLine(ry, from, to, 0);
314 if (redisplay != 2 && pt == 0) /* don't count/copy */
315 continue;
316 j = from;
317 #ifdef DW_CHARS
318 if (dw_right(ml, j, fore->w_encoding))
319 j--;
320 #endif
321 im = ml->image + j;
322 #ifdef FONT
323 fo = ml->font + j;
324 font = ASCII;
325 #endif
326 for (; j <= to; j++)
328 c = (unsigned char)*im++;
329 #ifdef FONT
330 cf = (unsigned char)*fo++;
331 # ifdef UTF8
332 if (fore->w_encoding == UTF8)
334 c |= cf << 8;
335 if (c == UCS_HIDDEN)
336 continue;
337 c = ToUtf8_comb(pt, c);
338 l += c;
339 if (pt)
340 pt += c;
341 continue;
343 # endif
344 # ifdef DW_CHARS
345 if (is_dw_font(cf))
347 c = c << 8 | (unsigned char)*im++;
348 fo++;
349 j++;
351 # endif
352 if (pastefont)
354 c = EncodeChar(pt, c | cf << 16, fore->w_encoding, &font);
355 l += c;
356 if (pt)
357 pt += c;
358 continue;
360 #endif /* FONT */
361 if (pt)
362 *pt++ = c;
363 l++;
365 #ifdef FONT
366 if (pastefont && font != ASCII)
368 if (pt)
370 strcpy(pt, "\033(B");
371 pt += 3;
373 l += 3;
375 #endif
376 if (i != y2 && (to != fore->w_width - 1 || ml->image[to + 1] == ' '))
379 * this code defines, what glues lines together
381 switch (markdata->nonl)
383 case 0: /* lines separated by newlines */
384 if (pt)
385 *pt++ = '\r';
386 l++;
387 if (join_with_cr)
389 if (pt)
390 *pt++ = '\n';
391 l++;
393 break;
394 case 1: /* nothing to separate lines */
395 break;
396 case 2: /* lines separated by blanks */
397 if (pt)
398 *pt++ = ' ';
399 l++;
400 break;
401 case 3: /* seperate by comma, for csh junkies */
402 if (pt)
403 *pt++ = ',';
404 l++;
405 break;
409 return l;
412 /* Check if two chars are identical. All digits are treated
413 * as same. Used for GetHistory()
416 static int
417 eq(a, b)
418 int a, b;
420 if (a == b)
421 return 1;
422 if (a == 0 || b == 0)
423 return 1;
424 if (a <= '9' && a >= '0' && b <= '9' && b >= '0')
425 return 1;
426 return 0;
430 /**********************************************************************/
433 GetHistory() /* return value 1 if copybuffer changed */
435 int i = 0, q = 0, xx, yy, x, y;
436 unsigned char *linep;
437 struct mline *ml;
439 ASSERT(display && fore);
440 x = fore->w_x;
441 if (x >= fore->w_width)
442 x = fore->w_width - 1;
443 y = fore->w_y + fore->w_histheight;
444 debug2("cursor is at x=%d, y=%d\n", x, y);
445 ml = WIN(y);
446 for (xx = x - 1, linep = ml->image + xx; xx >= 0; xx--)
447 if ((q = *linep--) != ' ' )
448 break;
449 debug3("%c at (%d,%d)\n", q, xx, y);
450 for (yy = y - 1; yy >= 0; yy--)
452 ml = WIN(yy);
453 linep = ml->image;
454 if (xx < 0 || eq(linep[xx], q))
455 { /* line is matching... */
456 for (i = fore->w_width - 1, linep += i; i >= x; i--)
457 if (*linep-- != ' ')
458 break;
459 if (i >= x)
460 break;
463 if (yy < 0)
464 return 0;
465 if (D_user->u_plop.buf)
466 UserFreeCopyBuffer(D_user);
467 if ((D_user->u_plop.buf = (char *)malloc((unsigned) (i - x + 2))) == NULL)
469 LMsg(0, "Not enough memory... Sorry.");
470 return 0;
472 bcopy((char *)linep - i + x + 1, D_user->u_plop.buf, i - x + 1);
473 D_user->u_plop.len = i - x + 1;
474 #ifdef ENCODINGS
475 D_user->u_plop.enc = fore->w_encoding;
476 #endif
477 return 1;
480 /**********************************************************************/
483 void
484 MarkRoutine()
486 int x, y;
488 ASSERT(fore && display && D_user);
490 debug2("MarkRoutine called: fore nr %d, display %s\n",
491 fore->w_number, D_usertty);
493 if (InitOverlayPage(sizeof(*markdata), &MarkLf, 1))
494 return;
495 flayer->l_encoding = fore->w_encoding;
496 markdata = (struct markdata *)flayer->l_data;
497 markdata->md_user = D_user; /* XXX: Correct? */
498 markdata->md_window = fore;
499 markdata->second = 0;
500 markdata->rep_cnt = 0;
501 markdata->append_mode = 0;
502 markdata->write_buffer = 0;
503 markdata->nonl = 0;
504 markdata->left_mar = 0;
505 markdata->right_mar = fore->w_width - 1;
506 markdata->hist_offset = fore->w_histheight;
507 x = fore->w_x;
508 y = D2W(fore->w_y);
509 if (x >= fore->w_width)
510 x = fore->w_width - 1;
512 LGotoPos(flayer, x, W2D(y));
513 LMsg(0, "Copy mode - Column %d Line %d(+%d) (%d,%d)",
514 x + 1, W2D(y + 1), fore->w_histheight, fore->w_width, fore->w_height);
515 markdata->cx = markdata->x1 = x;
516 markdata->cy = markdata->y1 = y;
517 flayer->l_x = x;
518 flayer->l_y = W2D(y);
521 static void
522 MarkProcess(inbufp,inlenp)
523 char **inbufp;
524 int *inlenp;
526 char *inbuf, *pt;
527 int inlen;
528 int cx, cy, x2, y2, j, yend;
529 int newcopylen = 0, od;
530 int in_mark;
531 int rep_cnt;
532 struct acluser *md_user;
535 char *extrap = 0, extrabuf[100];
538 markdata = (struct markdata *)flayer->l_data;
539 fore = markdata->md_window;
540 md_user = markdata->md_user;
541 if (inbufp == 0)
543 MarkAbort();
544 return;
547 LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
548 inbuf= *inbufp;
549 inlen= *inlenp;
550 pt = inbuf;
551 in_mark = 1;
552 while (in_mark && (inlen /* || extrap */))
555 if (extrap)
557 od = *extrap++;
558 if (*extrap == 0)
559 extrap = 0;
561 else
564 od = mark_key_tab[(int)(unsigned char)*pt++];
565 inlen--;
567 rep_cnt = markdata->rep_cnt;
568 if (od >= '0' && od <= '9' && !markdata->f_cmd.flag)
570 if (rep_cnt < 1001 && (od != '0' || rep_cnt != 0))
572 markdata->rep_cnt = 10 * rep_cnt + od - '0';
573 continue;
575 * Now what is that 1001 here? Well, we have a screen with
576 * 25 * 80 = 2000 characters. Movement is at most across the full
577 * screen. This we do with word by word movement, as character by
578 * character movement never steps over line boundaries. The most words
579 * we can place on the screen are 1000 single letter words. Thus 1001
580 * is sufficient. Users with bigger screens never write in single letter
581 * words, as they should be more advanced. jw.
582 * Oh, wrong. We still give even the experienced user a factor of ten.
586 cx = markdata->cx;
587 cy = markdata->cy;
589 if (markdata -> f_cmd.flag) {
590 debug2("searching for %c:%d\n",od,rep_cnt);
591 markdata->f_cmd.flag = 0;
592 markdata->rep_cnt = 0;
594 if (isgraph (od)) {
595 markdata->f_cmd.target = od;
596 rep_cnt = (rep_cnt) ? rep_cnt : 1;
597 nextchar(&cx, &cy, markdata->f_cmd.direction, od, rep_cnt );
598 revto(cx, cy);
599 continue;
603 switch (od)
605 case 'f': /* fall through */
606 case 'F': /* fall through */
607 case 't': /* fall through */
608 case 'T': /* fall through */
610 * Set f_cmd to do a search on the next key stroke.
611 * If we break, rep_cnt will be reset, so we
612 * continue instead. It might be cleaner to
613 * store the rep_count in f_cmd and
614 * break here so later followon code will be
615 * hit.
617 markdata->f_cmd.flag = 1;
618 markdata->f_cmd.direction = od;
619 debug("entering char search\n");
620 continue;
621 case ';':
622 if (!markdata->f_cmd.target)
623 break;
624 if (!rep_cnt)
625 rep_cnt = 1;
626 nextchar(&cx, &cy, markdata->f_cmd.direction, markdata->f_cmd.target, rep_cnt );
627 revto(cx, cy);
628 break;
629 case ',': {
630 int search_dir;
631 if (!markdata->f_cmd.target)
632 break;
633 if (!rep_cnt)
634 rep_cnt = 1;
635 switch (markdata->f_cmd.direction) {
636 case 't': search_dir = 'T'; break;
637 case 'T': search_dir = 't'; break;
638 case 'f': search_dir = 'F'; break;
639 case 'F': search_dir = 'f'; break;
641 nextchar(&cx, &cy, search_dir, markdata->f_cmd.target, rep_cnt );
642 revto(cx, cy);
643 break;
646 case 'o':
647 case 'x':
648 if (!markdata->second)
649 break;
650 markdata->cx = markdata->x1;
651 markdata->cy = markdata->y1;
652 markdata->x1 = cx;
653 markdata->y1 = cy;
654 revto(markdata->cx, markdata->cy);
655 break;
656 case '\014': /* CTRL-L Redisplay */
657 Redisplay(0);
658 LGotoPos(flayer, cx, W2D(cy));
659 break;
660 case 0202: /* M-C-b */
661 case '\010': /* CTRL-H Backspace */
662 case 'h':
663 if (rep_cnt == 0)
664 rep_cnt = 1;
665 revto(cx - rep_cnt, cy);
666 break;
667 case 0216: /* M-C-p */
668 case '\016': /* CTRL-N */
669 case 'j':
670 if (rep_cnt == 0)
671 rep_cnt = 1;
672 revto(cx, cy + rep_cnt);
673 break;
674 case '+':
675 if (rep_cnt == 0)
676 rep_cnt = 1;
677 j = cy + rep_cnt;
678 if (j > fore->w_histheight + fore->w_height - 1)
679 j = fore->w_histheight + fore->w_height - 1;
680 revto(linestart(j), j);
681 break;
682 case '-':
683 if (rep_cnt == 0)
684 rep_cnt = 1;
685 cy -= rep_cnt;
686 if (cy < 0)
687 cy = 0;
688 revto(linestart(cy), cy);
689 break;
690 case '^':
691 revto(linestart(cy), cy);
692 break;
693 case '\n':
694 revto(markdata->left_mar, cy + 1);
695 break;
696 case 0220: /* M-C-p */
697 case '\020': /* CTRL-P */
698 case 'k':
699 if (rep_cnt == 0)
700 rep_cnt = 1;
701 revto(cx, cy - rep_cnt);
702 break;
703 case 0206: /* M-C-f */
704 case 'l':
705 if (rep_cnt == 0)
706 rep_cnt = 1;
707 revto(cx + rep_cnt, cy);
708 break;
709 case '\001': /* CTRL-A from tcsh/emacs */
710 case '0':
711 revto(markdata->left_mar, cy);
712 break;
713 case '\004': /* CTRL-D down half screen */
714 if (rep_cnt == 0)
715 rep_cnt = (fore->w_height + 1) >> 1;
716 revto_line(cx, cy + rep_cnt, W2D(cy));
717 break;
718 case '$':
719 revto(lineend(cy), cy);
720 break;
721 case '\022': /* CTRL-R emacs style backwards search */
722 ISearch(-1);
723 in_mark = 0;
724 break;
725 case '\023': /* CTRL-S emacs style search */
726 ISearch(1);
727 in_mark = 0;
728 break;
729 case '\025': /* CTRL-U up half screen */
730 if (rep_cnt == 0)
731 rep_cnt = (fore->w_height + 1) >> 1;
732 revto_line(cx, cy - rep_cnt, W2D(cy));
733 break;
734 case '\007': /* CTRL-G show cursorpos */
735 if (markdata->left_mar == 0 && markdata->right_mar == fore->w_width - 1)
736 LMsg(0, "Column %d Line %d(+%d)", cx+1, W2D(cy)+1,
737 markdata->hist_offset);
738 else
739 LMsg(0, "Column %d(%d..%d) Line %d(+%d)", cx+1,
740 markdata->left_mar+1, markdata->right_mar+1, W2D(cy)+1, markdata->hist_offset);
741 break;
742 case '\002': /* CTRL-B back one page */
743 if (rep_cnt == 0)
744 rep_cnt = 1;
745 rep_cnt *= fore->w_height;
746 revto(cx, cy - rep_cnt);
747 break;
748 case '\006': /* CTRL-F forward one page */
749 if (rep_cnt == 0)
750 rep_cnt = 1;
751 rep_cnt *= fore->w_height;
752 revto(cx, cy + rep_cnt);
753 break;
754 case '\005': /* CTRL-E scroll up */
755 if (rep_cnt == 0)
756 rep_cnt = 1;
757 rep_cnt = MarkScrollUpDisplay(rep_cnt);
758 if (cy < D2W(0))
759 revto(cx, D2W(0));
760 else
761 LGotoPos(flayer, cx, W2D(cy));
762 break;
763 case '\031': /* CTRL-Y scroll down */
764 if (rep_cnt == 0)
765 rep_cnt = 1;
766 rep_cnt = MarkScrollDownDisplay(rep_cnt);
767 if (cy > D2W(fore->w_height-1))
768 revto(cx, D2W(fore->w_height-1));
769 else
770 LGotoPos(flayer, cx, W2D(cy));
771 break;
772 case '@':
773 /* it may be usefull to have a key that does nothing */
774 break;
775 case '%':
776 rep_cnt--;
777 /* rep_cnt is a percentage for the history buffer */
778 if (rep_cnt < 0)
779 rep_cnt = 0;
780 if (rep_cnt > 100)
781 rep_cnt = 100;
782 revto_line(markdata->left_mar, (rep_cnt * (fore->w_histheight + fore->w_height)) / 100, (fore->w_height - 1) / 2);
783 break;
784 case 0201:
785 case 'g':
786 rep_cnt = 1;
787 /* FALLTHROUGH */
788 case 0205:
789 case 'G':
790 /* rep_cnt is here the WIN line number */
791 if (rep_cnt == 0)
792 rep_cnt = fore->w_histheight + fore->w_height;
793 revto_line(markdata->left_mar, --rep_cnt, (fore->w_height - 1) / 2);
794 break;
795 case 'H':
796 revto(markdata->left_mar, D2W(0));
797 break;
798 case 'M':
799 revto(markdata->left_mar, D2W((fore->w_height - 1) / 2));
800 break;
801 case 'L':
802 revto(markdata->left_mar, D2W(fore->w_height - 1));
803 break;
804 case '|':
805 revto(--rep_cnt, cy);
806 break;
807 case 'w':
808 if (rep_cnt == 0)
809 rep_cnt = 1;
810 nextword(&cx, &cy, NW_MUSTMOVE, rep_cnt);
811 revto(cx, cy);
812 break;
813 case 'e':
814 case 'E':
815 if (rep_cnt == 0)
816 rep_cnt = 1;
817 nextword(&cx, &cy, NW_ENDOFWORD|NW_MUSTMOVE | (od == 'E' ? NW_BIG : 0), rep_cnt);
818 revto(cx, cy);
819 break;
820 case 'b':
821 case 'B':
822 if (rep_cnt == 0)
823 rep_cnt = 1;
824 nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD|NW_MUSTMOVE | (od == 'B' ? NW_BIG : 0), rep_cnt);
825 revto(cx, cy);
826 break;
827 case 'a':
828 markdata->append_mode = 1 - markdata->append_mode;
829 debug1("append mode %d--\n", markdata->append_mode);
830 LMsg(0, (markdata->append_mode) ? ":set append" : ":set noappend");
831 break;
832 case 'v':
833 case 'V':
834 /* this sets start column to column 9 for VI :set nu users */
835 if (markdata->left_mar == 8)
836 rep_cnt = 1;
837 else
838 rep_cnt = 9;
839 /* FALLTHROUGH */
840 case 'c':
841 case 'C':
842 /* set start column (c) and end column (C) */
843 if (markdata->second)
845 rem(markdata->x1, markdata->y1, cx, cy, 1, (char *)0, fore->w_height-1); /* Hack */
846 markdata->second = 1; /* rem turns off second */
848 rep_cnt--;
849 if (rep_cnt < 0)
850 rep_cnt = cx;
851 if (od != 'C')
853 markdata->left_mar = rep_cnt;
854 if (markdata->left_mar > markdata->right_mar)
855 markdata->left_mar = markdata->right_mar;
857 else
859 markdata->right_mar = rep_cnt;
860 if (markdata->left_mar > markdata->right_mar)
861 markdata->right_mar = markdata->left_mar;
863 if (markdata->second)
865 markdata->cx = markdata->x1; markdata->cy = markdata->y1;
866 revto(cx, cy);
868 if (od == 'v' || od == 'V')
869 LMsg(0, (markdata->left_mar != 8) ? ":set nonu" : ":set nu");
870 break;
871 case 'J':
872 /* how do you join lines in VI ? */
873 markdata->nonl = (markdata->nonl + 1) % 4;
874 switch (markdata->nonl)
876 case 0:
877 if (join_with_cr)
878 LMsg(0, "Multiple lines (CR/LF)");
879 else
880 LMsg(0, "Multiple lines (LF)");
881 break;
882 case 1:
883 LMsg(0, "Lines joined");
884 break;
885 case 2:
886 LMsg(0, "Lines joined with blanks");
887 break;
888 case 3:
889 LMsg(0, "Lines joined with comma");
890 break;
892 break;
893 case '/':
894 Search(1);
895 in_mark = 0;
896 break;
897 case '?':
898 Search(-1);
899 in_mark = 0;
900 break;
901 case 'n':
902 Search(0);
903 break;
904 case 'N':
905 markdata->isdir = -markdata->isdir;
906 Search(0);
907 markdata->isdir = -markdata->isdir;
908 break;
909 case 'y':
910 case 'Y':
911 if (markdata->second == 0)
913 revto(linestart(cy), cy);
914 markdata->second++;
915 cx = markdata->x1 = markdata->cx;
916 cy = markdata->y1 = markdata->cy;
918 if (--rep_cnt > 0)
919 revto(cx, cy + rep_cnt);
920 revto(lineend(markdata->cy), markdata->cy);
921 if (od == 'y')
922 break;
923 /* FALLTHROUGH */
924 case 'W':
925 if (od == 'W')
927 if (rep_cnt == 0)
928 rep_cnt = 1;
929 if (!markdata->second)
931 nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD, 1);
932 revto(cx, cy);
933 markdata->second++;
934 cx = markdata->x1 = markdata->cx;
935 cy = markdata->y1 = markdata->cy;
937 nextword(&cx, &cy, NW_ENDOFWORD, rep_cnt);
938 revto(cx, cy);
940 cx = markdata->cx;
941 cy = markdata->cy;
942 /* FALLTHROUGH */
943 case 'A':
944 if (od == 'A')
945 markdata->append_mode = 1;
946 /* FALLTHROUGH */
947 case '>':
948 if (od == '>')
949 markdata->write_buffer = 1;
950 /* FALLTHROUGH */
951 case ' ':
952 case '\r':
953 if (!markdata->second)
955 markdata->second++;
956 markdata->x1 = cx;
957 markdata->y1 = cy;
958 revto(cx, cy);
959 LMsg(0, "First mark set - Column %d Line %d", cx+1, W2D(cy)+1);
960 break;
962 else
964 int append_mode = markdata->append_mode;
965 int write_buffer = markdata->write_buffer;
967 x2 = cx;
968 y2 = cy;
969 newcopylen = rem(markdata->x1, markdata->y1, x2, y2, 2, (char *)0, 0); /* count */
970 if (md_user->u_plop.buf && !append_mode)
971 UserFreeCopyBuffer(md_user);
972 yend = fore->w_height - 1;
973 if (fore->w_histheight - markdata->hist_offset < fore->w_height)
975 markdata->second = 0;
976 yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
978 if (newcopylen > 0)
980 /* the +3 below is for : cr + lf + \0 */
981 if (md_user->u_plop.buf)
982 md_user->u_plop.buf = realloc(md_user->u_plop.buf,
983 (unsigned) (md_user->u_plop.len + newcopylen + 3));
984 else
986 md_user->u_plop.len = 0;
987 md_user->u_plop.buf = malloc((unsigned) (newcopylen + 3));
989 if (!md_user->u_plop.buf)
991 MarkAbort();
992 in_mark = 0;
993 LMsg(0, "Not enough memory... Sorry.");
994 md_user->u_plop.len = 0;
995 md_user->u_plop.buf = 0;
996 break;
998 if (append_mode)
1000 switch (markdata->nonl)
1003 * this code defines, what glues lines together
1005 case 0:
1006 if (join_with_cr)
1008 md_user->u_plop.buf[md_user->u_plop.len] = '\r';
1009 md_user->u_plop.len++;
1011 md_user->u_plop.buf[md_user->u_plop.len] = '\n';
1012 md_user->u_plop.len++;
1013 break;
1014 case 1:
1015 break;
1016 case 2:
1017 md_user->u_plop.buf[md_user->u_plop.len] = ' ';
1018 md_user->u_plop.len++;
1019 break;
1020 case 3:
1021 md_user->u_plop.buf[md_user->u_plop.len] = ',';
1022 md_user->u_plop.len++;
1023 break;
1026 md_user->u_plop.len += rem(markdata->x1, markdata->y1, x2, y2,
1027 markdata->hist_offset == fore->w_histheight,
1028 md_user->u_plop.buf + md_user->u_plop.len, yend);
1029 #ifdef ENCODINGS
1030 md_user->u_plop.enc = fore->w_encoding;
1031 #endif
1033 if (markdata->hist_offset != fore->w_histheight)
1035 LAY_CALL_UP(LRefreshAll(flayer, 0));
1037 ExitOverlayPage();
1038 if (append_mode)
1039 LMsg(0, "Appended %d characters to buffer",
1040 newcopylen);
1041 else
1042 LMsg(0, "Copied %d characters into buffer", md_user->u_plop.len);
1043 if (write_buffer)
1044 WriteFile(md_user, (char *)0, DUMP_EXCHANGE);
1045 in_mark = 0;
1046 break;
1048 default:
1049 MarkAbort();
1050 LMsg(0, "Copy mode aborted");
1051 in_mark = 0;
1052 break;
1054 if (in_mark) /* markdata may be freed */
1055 markdata->rep_cnt = 0;
1057 if (in_mark)
1059 flayer->l_x = markdata->cx;
1060 flayer->l_y = W2D(markdata->cy);
1062 *inbufp = pt;
1063 *inlenp = inlen;
1066 void revto(tx, ty)
1067 int tx, ty;
1069 revto_line(tx, ty, -1);
1072 /* tx, ty: WINDOW, line: DISPLAY */
1073 void revto_line(tx, ty, line)
1074 int tx, ty, line;
1076 int fx, fy;
1077 int x, y, t, revst, reven, qq, ff, tt, st, en, ce = 0;
1078 int ystart = 0, yend = fore->w_height-1;
1079 int i, ry;
1080 unsigned char *wi;
1081 struct mline *ml;
1082 struct mchar mc;
1084 if (tx < 0)
1085 tx = 0;
1086 else if (tx > fore->w_width - 1)
1087 tx = fore->w_width -1;
1088 if (ty < 0)
1089 ty = 0;
1090 else if (ty > fore->w_histheight + fore->w_height - 1)
1091 ty = fore->w_histheight + fore->w_height - 1;
1093 fx = markdata->cx; fy = markdata->cy;
1095 #ifdef DW_CHARS
1096 /* don't just move inside of a kanji, the user wants to see something */
1097 ml = WIN(ty);
1098 if (ty == fy && fx + 1 == tx && dw_right(ml, tx, fore->w_encoding) && tx < D_width - 1)
1099 tx++;
1100 if (ty == fy && fx - 1 == tx && dw_right(ml, fx, fore->w_encoding) && tx)
1101 tx--;
1102 #endif
1104 markdata->cx = tx; markdata->cy = ty;
1107 * if we go to a position that is currently offscreen
1108 * then scroll the screen
1110 i = 0;
1111 if (line >= 0 && line < fore->w_height)
1112 i = W2D(ty) - line;
1113 else if (ty < markdata->hist_offset)
1114 i = ty - markdata->hist_offset;
1115 else if (ty > markdata->hist_offset + (fore->w_height - 1))
1116 i = ty - markdata->hist_offset - (fore->w_height - 1);
1117 if (i > 0)
1118 yend -= MarkScrollUpDisplay(i);
1119 else if (i < 0)
1120 ystart += MarkScrollDownDisplay(-i);
1122 if (markdata->second == 0)
1124 LGotoPos(flayer, tx, W2D(ty));
1125 return;
1128 qq = markdata->x1 + markdata->y1 * fore->w_width;
1129 ff = fx + fy * fore->w_width; /* "from" offset in WIN coords */
1130 tt = tx + ty * fore->w_width; /* "to" offset in WIN coords*/
1132 if (ff > tt)
1134 st = tt; en = ff;
1135 x = tx; y = ty;
1137 else
1139 st = ff; en = tt;
1140 x = fx; y = fy;
1142 if (st > qq)
1144 st++;
1145 x++;
1147 if (en < qq)
1148 en--;
1149 if (tt > qq)
1151 revst = qq; reven = tt;
1153 else
1155 revst = tt; reven = qq;
1157 ry = y - markdata->hist_offset;
1158 if (ry < ystart)
1160 y += (ystart - ry);
1161 x = 0;
1162 st = y * fore->w_width;
1163 ry = ystart;
1165 ml = WIN(y);
1166 for (t = st; t <= en; t++, x++)
1168 if (x >= fore->w_width)
1170 x = 0;
1171 y++, ry++;
1172 ml = WIN(y);
1174 if (ry > yend)
1175 break;
1176 if (t == st || x == 0)
1178 wi = ml->image + fore->w_width;
1179 for (ce = fore->w_width; ce >= 0; ce--, wi--)
1180 if (*wi != ' ')
1181 break;
1183 if (x <= ce && x >= markdata->left_mar && x <= markdata->right_mar)
1185 #ifdef DW_CHARS
1186 if (dw_right(ml, x, fore->w_encoding))
1188 if (t == revst)
1189 revst--;
1190 t--;
1191 x--;
1193 #endif
1194 if (t >= revst && t <= reven)
1196 mc = mchar_so;
1197 #ifdef FONT
1198 if (pastefont)
1199 mc.font = ml->font[x];
1200 #endif
1201 mc.image = ml->image[x];
1203 else
1204 copy_mline2mchar(&mc, ml, x);
1205 #ifdef DW_CHARS
1206 if (dw_left(ml, x, fore->w_encoding))
1208 mc.mbcs = ml->image[x + 1];
1209 LPutChar(flayer, &mc, x, W2D(y));
1210 t++;
1212 #endif
1213 LPutChar(flayer, &mc, x, W2D(y));
1214 #ifdef DW_CHARS
1215 if (dw_left(ml, x, fore->w_encoding))
1216 x++;
1217 #endif
1220 LGotoPos(flayer, tx, W2D(ty));
1223 static void
1224 MarkAbort()
1226 int yend, redisp;
1228 debug("MarkAbort\n");
1229 markdata = (struct markdata *)flayer->l_data;
1230 fore = markdata->md_window;
1231 yend = fore->w_height - 1;
1232 redisp = markdata->second;
1233 if (fore->w_histheight - markdata->hist_offset < fore->w_height)
1235 markdata->second = 0;
1236 yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
1238 if (markdata->hist_offset != fore->w_histheight)
1240 LAY_CALL_UP(LRefreshAll(flayer, 0));
1242 else
1244 rem(markdata->x1, markdata->y1, markdata->cx, markdata->cy, redisp, (char *)0, yend);
1246 ExitOverlayPage();
1250 static void
1251 MarkRedisplayLine(y, xs, xe, isblank)
1252 int y; /* NOTE: y is in DISPLAY coords system! */
1253 int xs, xe;
1254 int isblank;
1256 int wy, x, i, rm;
1257 int sta, sto, cp; /* NOTE: these 3 are in WINDOW coords system */
1258 unsigned char *wi;
1259 struct mline *ml;
1260 struct mchar mchar_marked;
1262 if (y < 0) /* No special full page handling */
1263 return;
1265 markdata = (struct markdata *)flayer->l_data;
1266 fore = markdata->md_window;
1268 mchar_marked = mchar_so;
1270 wy = D2W(y);
1271 ml = WIN(wy);
1273 if (markdata->second == 0)
1275 if (dw_right(ml, xs, fore->w_encoding) && xs > 0)
1276 xs--;
1277 if (dw_left(ml, xe, fore->w_encoding) && xe < fore->w_width - 1)
1278 xe++;
1279 if (xs == 0 && y > 0 && wy > 0 && WIN(wy - 1)->image[flayer->l_width] == 0)
1280 LCDisplayLineWrap(flayer, ml, y, xs, xe, isblank);
1281 else
1282 LCDisplayLine(flayer, ml, y, xs, xe, isblank);
1283 return;
1286 sta = markdata->y1 * fore->w_width + markdata->x1;
1287 sto = markdata->cy * fore->w_width + markdata->cx;
1288 if (sta > sto)
1290 i=sta; sta=sto; sto=i;
1292 cp = wy * fore->w_width + xs;
1294 rm = markdata->right_mar;
1295 for (x = fore->w_width, wi = ml->image + fore->w_width; x >= 0; x--, wi--)
1296 if (*wi != ' ')
1297 break;
1298 if (x < rm)
1299 rm = x;
1301 for (x = xs; x <= xe; x++, cp++)
1302 if (cp >= sta && x >= markdata->left_mar)
1303 break;
1304 #ifdef DW_CHARS
1305 if (dw_right(ml, x, fore->w_encoding))
1306 x--;
1307 #endif
1308 if (x > xs)
1309 LCDisplayLine(flayer, ml, y, xs, x - 1, isblank);
1310 for (; x <= xe; x++, cp++)
1312 if (cp > sto || x > rm)
1313 break;
1314 #ifdef FONT
1315 if (pastefont)
1316 mchar_marked.font = ml->font[x];
1317 #endif
1318 mchar_marked.image = ml->image[x];
1319 #ifdef DW_CHARS
1320 mchar_marked.mbcs = 0;
1321 if (dw_left(ml, x, fore->w_encoding))
1323 mchar_marked.mbcs = ml->image[x + 1];
1324 cp++;
1326 #endif
1327 LPutChar(flayer, &mchar_marked, x, y);
1328 #ifdef DW_CHARS
1329 if (dw_left(ml, x, fore->w_encoding))
1330 x++;
1331 #endif
1333 if (x <= xe)
1334 LCDisplayLine(flayer, ml, y, x, xe, isblank);
1339 * This ugly routine is to speed up GotoPos()
1341 static int
1342 MarkRewrite(ry, xs, xe, rend, doit)
1343 int ry, xs, xe, doit;
1344 struct mchar *rend;
1346 int dx, x, y, st, en, t, rm;
1347 unsigned char *i;
1348 struct mline *ml;
1349 struct mchar mchar_marked;
1351 mchar_marked = mchar_so;
1353 debug3("MarkRewrite %d, %d-%d\n", ry, xs, xe);
1354 markdata = (struct markdata *)flayer->l_data;
1355 fore = markdata->md_window;
1356 y = D2W(ry);
1357 ml = WIN(y);
1358 #ifdef UTF8
1359 if (fore->w_encoding && fore->w_encoding != UTF8 && D_encoding == UTF8 && ContainsSpecialDeffont(ml, xs, xe, fore->w_encoding))
1360 return EXPENSIVE;
1361 #endif
1362 dx = xe - xs + 1;
1363 if (doit)
1365 i = ml->image + xs;
1366 while (dx--)
1367 PUTCHAR(*i++);
1368 return 0;
1371 if (markdata->second == 0)
1372 st = en = -1;
1373 else
1375 st = markdata->y1 * fore->w_width + markdata->x1;
1376 en = markdata->cy * fore->w_width + markdata->cx;
1377 if (st > en)
1379 t = st; st = en; en = t;
1382 t = y * fore->w_width + xs;
1383 for (rm = fore->w_width, i = ml->image + fore->w_width; rm >= 0; rm--)
1384 if (*i-- != ' ')
1385 break;
1386 if (rm > markdata->right_mar)
1387 rm = markdata->right_mar;
1388 x = xs;
1389 while (dx--)
1391 if (t >= st && t <= en && x >= markdata->left_mar && x <= rm)
1393 #ifdef FONT
1394 if (pastefont)
1395 mchar_marked.font = ml->font[x];
1396 #endif
1397 rend->image = mchar_marked.image;
1398 if (!cmp_mchar(rend, &mchar_marked))
1399 return EXPENSIVE;
1401 else
1403 rend->image = ml->image[x];
1404 if (!cmp_mchar_mline(rend, ml, x))
1405 return EXPENSIVE;
1407 x++;
1409 return xe - xs + 1;
1414 * scroll the screen contents up/down.
1416 static int MarkScrollUpDisplay(n)
1417 int n;
1419 int i;
1421 debug1("MarkScrollUpDisplay(%d)\n", n);
1422 if (n <= 0)
1423 return 0;
1424 if (n > fore->w_histheight - markdata->hist_offset)
1425 n = fore->w_histheight - markdata->hist_offset;
1426 markdata->hist_offset += n;
1427 i = (n < flayer->l_height) ? n : (flayer->l_height);
1428 LScrollV(flayer, i, 0, flayer->l_height - 1, 0);
1429 while (i-- > 0)
1430 MarkRedisplayLine(flayer->l_height - i - 1, 0, flayer->l_width - 1, 1);
1431 return n;
1434 static int
1435 MarkScrollDownDisplay(n)
1436 int n;
1438 int i;
1440 debug1("MarkScrollDownDisplay(%d)\n", n);
1441 if (n <= 0)
1442 return 0;
1443 if (n > markdata->hist_offset)
1444 n = markdata->hist_offset;
1445 markdata->hist_offset -= n;
1446 i = (n < flayer->l_height) ? n : (flayer->l_height);
1447 LScrollV(flayer, -i, 0, fore->w_height - 1, 0);
1448 while (i-- > 0)
1449 MarkRedisplayLine(i, 0, flayer->l_width - 1, 1);
1450 return n;
1454 InMark()
1456 if (flayer && flayer->l_layfn == &MarkLf)
1457 return 1;
1458 return 0;
1461 void
1462 MakePaster(pa, buf, len, bufiscopy)
1463 struct paster *pa;
1464 char *buf;
1465 int len;
1466 int bufiscopy;
1468 FreePaster(pa);
1469 pa->pa_pasteptr = buf;
1470 pa->pa_pastelen = len;
1471 if (bufiscopy)
1472 pa->pa_pastebuf = buf;
1473 pa->pa_pastelayer = flayer;
1474 DoProcess(Layer2Window(flayer), &pa->pa_pasteptr, &pa->pa_pastelen, pa);
1477 void
1478 FreePaster(pa)
1479 struct paster *pa;
1481 if (pa->pa_pastebuf)
1482 free(pa->pa_pastebuf);
1483 pa->pa_pastebuf = 0;
1484 pa->pa_pasteptr = 0;
1485 pa->pa_pastelen = 0;
1486 pa->pa_pastelayer = 0;
1487 evdeq(&pa->pa_slowev);
1490 #endif /* COPY_PASTE */