9ff7b6527eeec4b7fcef37e758b0bf7aa1d750c3
[screen-lua.git] / src / mark.c
blob9ff7b6527eeec4b7fcef37e758b0bf7aa1d750c3
1 /* Copyright (c) 2008
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 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include <sys/types.h>
30 #include <ctype.h>
32 #include "config.h"
33 #include "screen.h"
34 #include "mark.h"
35 #include "extern.h"
37 #ifdef COPY_PASTE
40 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
42 * WARNING: these routines use the global variables "fore" and
43 * "flayer" to make things easier.
45 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
48 static int is_letter __P((int));
49 static void nextword __P((int *, int *, int, int));
50 static int linestart __P((int));
51 static int lineend __P((int));
52 static int rem __P((int, int , int , int , int , char *, int));
53 static int eq __P((int, int ));
54 static int MarkScrollDownDisplay __P((int));
55 static int MarkScrollUpDisplay __P((int));
57 static void MarkProcess __P((char **, int *));
58 static void MarkAbort __P((void));
59 static void MarkRedisplayLine __P((int, int, int, int));
60 static int MarkRewrite __P((int, int, int, struct mchar *, int));
62 extern struct layer *flayer;
63 extern struct display *display, *displays;
64 extern struct win *fore;
65 extern struct mline mline_blank, mline_null;
66 extern struct mchar mchar_so;
68 #ifdef FONT
69 int pastefont = 1;
70 #endif
72 struct LayFuncs MarkLf =
74 MarkProcess,
75 MarkAbort,
76 MarkRedisplayLine,
77 DefClearLine,
78 MarkRewrite,
79 DefResize,
80 DefRestore
83 int join_with_cr = 0;
84 int compacthist = 0;
86 unsigned char mark_key_tab[256]; /* this array must be initialised first! */
88 static struct markdata *markdata;
92 * VI like is_letter: 0 - whitespace
93 * 1 - letter
94 * 2 - other
96 static int is_letter(c)
97 char c;
99 if ((c >= 'a' && c <= 'z') ||
100 (c >= 'A' && c <= 'Z') ||
101 (c >= '0' && c <= '9') ||
102 c == '_' || c == '.' ||
103 c == '@' || c == ':' ||
104 c == '%' || c == '!' ||
105 c == '-' || c == '+')
106 /* thus we can catch email-addresses as a word :-) */
107 return 1;
108 else if (c != ' ')
109 return 2;
110 return 0;
113 static int
114 linestart(y)
115 int y;
117 register int x;
118 register unsigned char *i;
120 for (x = markdata->left_mar, i = WIN(y)->image + x; x < fore->w_width - 1; x++)
121 if (*i++ != ' ')
122 break;
123 if (x == fore->w_width - 1)
124 x = markdata->left_mar;
125 return x;
128 static int
129 lineend(y)
130 int y;
132 register int x;
133 register unsigned char *i;
135 for (x = markdata->right_mar, i = WIN(y)->image + x; x >= 0; x--)
136 if (*i-- != ' ')
137 break;
138 if (x < 0)
139 x = markdata->left_mar;
140 return x;
144 * nextchar sets *xp to the num-th occurrence of the target in the line.
146 * Returns -1 if the target doesn't appear num times, 0 otherwise.
148 static int
149 nextchar(int *xp, int *yp, int direction, char target, int num)
151 int width; /* width of the current window. */
152 int x; /* x coordinate of the current cursor position. */
153 int step; /* amount to increment x (+1 or -1) */
154 int adjust; /* Final adjustment of cursor position. */
155 char *displayed_line; /* Line in which search takes place. */
157 debug("nextchar\n");
159 x = *xp;
160 adjust = 0;
161 width = fore->w_width;
162 displayed_line = (char *)WIN(*yp) -> image;
164 switch(direction) {
165 case 't': adjust = -1; /* fall through */
166 case 'f': step = 1; /* fall through */
167 break;
168 case 'T': adjust = 1; /* fall through */
169 case 'F': step = -1; /* fall through */
170 break;
171 default:
172 ASSERT(0);
175 x += step;
177 debug1("ml->image = %s\n", displayed_line);
178 debug2("num = %d, width = %d\n",num, width);
179 debug2("x = %d target = %c\n", x, target );
181 for ( ;x>=0 && x <= width; x += step) {
182 if (displayed_line[x] == target) {
183 if (--num == 0) {
184 *xp = x + adjust;
185 return 0;
189 return -1;
193 * nextword calculates the cursor position of the num'th word.
194 * If the cursor is on a word, it counts as the first.
195 * NW_BACK: search backward
196 * NW_ENDOFWORD: find the end of the word
197 * NW_MUSTMOVE: move at least one char
198 * NW_BIG: match WORDs not words
201 #define NW_BACK (1<<0)
202 #define NW_ENDOFWORD (1<<1)
203 #define NW_MUSTMOVE (1<<2)
204 #define NW_BIG (1<<3)
208 static void
209 nextword(xp, yp, flags, num)
210 int *xp, *yp, flags, num;
212 int xx = fore->w_width, yy = fore->w_histheight + fore->w_height;
213 register int sx, oq, q, x, y;
214 struct mline *ml;
216 x = *xp;
217 y = *yp;
218 sx = (flags & NW_BACK) ? -1 : 1;
219 if ((flags & NW_ENDOFWORD) && (flags & NW_MUSTMOVE))
220 x += sx;
221 ml = WIN(y);
222 for (oq = -1; ; x += sx, oq = q)
224 if (x >= xx || x < 0)
225 q = 0;
226 else if (flags & NW_BIG)
227 q = ml->image[x] == ' ';
228 else
229 q = is_letter(ml->image[x]);
230 if (oq >= 0 && oq != q)
232 if (oq == 0 || !(flags & NW_ENDOFWORD))
233 *xp = x;
234 else
235 *xp = x-sx;
236 *yp = y;
237 if ((!(flags & NW_ENDOFWORD) && q) ||
238 ((flags & NW_ENDOFWORD) && oq))
240 if (--num <= 0)
241 return;
244 if (x == xx)
246 x = -1;
247 if (++y >= yy)
248 return;
249 ml = WIN(y);
251 else if (x < 0)
253 x = xx;
254 if (--y < 0)
255 return;
256 ml = WIN(y);
263 * y1, y2 are WIN coordinates
265 * redisplay: 0 - just copy
266 * 1 - redisplay + copy
267 * 2 - count + copy, don't redisplay
270 static int
271 rem(x1, y1, x2, y2, redisplay, pt, yend)
272 int x1, y1, x2, y2, redisplay, yend;
273 char *pt;
275 int i, j, from, to, ry, c;
276 int l = 0;
277 unsigned char *im;
278 struct mline *ml;
279 #ifdef FONT
280 int cf, font;
281 unsigned char *fo;
282 #endif
284 markdata->second = 0;
285 if (y2 < y1 || ((y2 == y1) && (x2 < x1)))
287 i = y2;
288 y2 = y1;
289 y1 = i;
290 i = x2;
291 x2 = x1;
292 x1 = i;
294 ry = y1 - markdata->hist_offset;
296 i = y1;
297 if (redisplay != 2 && pt == 0 && ry <0)
299 i -= ry;
300 ry = 0;
302 for (; i <= y2; i++, ry++)
304 if (redisplay != 2 && pt == 0 && ry > yend)
305 break;
306 ml = WIN(i);
307 from = (i == y1) ? x1 : 0;
308 if (from < markdata->left_mar)
309 from = markdata->left_mar;
310 for (to = fore->w_width, im = ml->image + to; to >= 0; to--)
311 if (*im-- != ' ')
312 break;
313 if (i == y2 && x2 < to)
314 to = x2;
315 if (to > markdata->right_mar)
316 to = markdata->right_mar;
317 if (redisplay == 1 && from <= to && ry >=0 && ry <= yend)
318 MarkRedisplayLine(ry, from, to, 0);
319 if (redisplay != 2 && pt == 0) /* don't count/copy */
320 continue;
321 j = from;
322 #ifdef DW_CHARS
323 if (dw_right(ml, j, fore->w_encoding))
324 j--;
325 #endif
326 im = ml->image + j;
327 #ifdef FONT
328 fo = ml->font + j;
329 font = ASCII;
330 #endif
331 for (; j <= to; j++)
333 c = (unsigned char)*im++;
334 #ifdef FONT
335 cf = (unsigned char)*fo++;
336 # ifdef UTF8
337 if (fore->w_encoding == UTF8)
339 c |= cf << 8;
340 if (c == UCS_HIDDEN)
341 continue;
342 c = ToUtf8_comb(pt, c);
343 l += c;
344 if (pt)
345 pt += c;
346 continue;
348 # endif
349 # ifdef DW_CHARS
350 if (is_dw_font(cf))
352 c = c << 8 | (unsigned char)*im++;
353 fo++;
354 j++;
356 # endif
357 if (pastefont)
359 c = EncodeChar(pt, c | cf << 16, fore->w_encoding, &font);
360 l += c;
361 if (pt)
362 pt += c;
363 continue;
365 #endif /* FONT */
366 if (pt)
367 *pt++ = c;
368 l++;
370 #ifdef FONT
371 if (pastefont && font != ASCII)
373 if (pt)
375 strcpy(pt, "\033(B");
376 pt += 3;
378 l += 3;
380 #endif
381 if (i != y2 && (to != fore->w_width - 1 || ml->image[to + 1] == ' '))
384 * this code defines, what glues lines together
386 switch (markdata->nonl)
388 case 0: /* lines separated by newlines */
389 if (pt)
390 *pt++ = '\r';
391 l++;
392 if (join_with_cr)
394 if (pt)
395 *pt++ = '\n';
396 l++;
398 break;
399 case 1: /* nothing to separate lines */
400 break;
401 case 2: /* lines separated by blanks */
402 if (pt)
403 *pt++ = ' ';
404 l++;
405 break;
406 case 3: /* seperate by comma, for csh junkies */
407 if (pt)
408 *pt++ = ',';
409 l++;
410 break;
414 return l;
417 /* Check if two chars are identical. All digits are treated
418 * as same. Used for GetHistory()
421 static int
422 eq(a, b)
423 int a, b;
425 if (a == b)
426 return 1;
427 if (a == 0 || b == 0)
428 return 1;
429 if (a <= '9' && a >= '0' && b <= '9' && b >= '0')
430 return 1;
431 return 0;
435 /**********************************************************************/
438 GetHistory() /* return value 1 if copybuffer changed */
440 int i = 0, q = 0, xx, yy, x, y;
441 unsigned char *linep;
442 struct mline *ml;
444 ASSERT(display && fore);
445 x = fore->w_x;
446 if (x >= fore->w_width)
447 x = fore->w_width - 1;
448 y = fore->w_y + fore->w_histheight;
449 debug2("cursor is at x=%d, y=%d\n", x, y);
450 ml = WIN(y);
451 for (xx = x - 1, linep = ml->image + xx; xx >= 0; xx--)
452 if ((q = *linep--) != ' ' )
453 break;
454 debug3("%c at (%d,%d)\n", q, xx, y);
455 for (yy = y - 1; yy >= 0; yy--)
457 ml = WIN(yy);
458 linep = ml->image;
459 if (xx < 0 || eq(linep[xx], q))
460 { /* line is matching... */
461 for (i = fore->w_width - 1, linep += i; i >= x; i--)
462 if (*linep-- != ' ')
463 break;
464 if (i >= x)
465 break;
468 if (yy < 0)
469 return 0;
470 if (D_user->u_plop.buf)
471 UserFreeCopyBuffer(D_user);
472 if ((D_user->u_plop.buf = (char *)malloc((unsigned) (i - x + 2))) == NULL)
474 LMsg(0, "Not enough memory... Sorry.");
475 return 0;
477 bcopy((char *)linep - i + x + 1, D_user->u_plop.buf, i - x + 1);
478 D_user->u_plop.len = i - x + 1;
479 #ifdef ENCODINGS
480 D_user->u_plop.enc = fore->w_encoding;
481 #endif
482 return 1;
485 /**********************************************************************/
488 void
489 MarkRoutine()
491 int x, y;
493 ASSERT(fore && display && D_user);
495 debug2("MarkRoutine called: fore nr %d, display %s\n",
496 fore->w_number, D_usertty);
498 if (InitOverlayPage(sizeof(*markdata), &MarkLf, 1))
499 return;
500 flayer->l_encoding = fore->w_encoding;
501 markdata = (struct markdata *)flayer->l_data;
502 markdata->md_user = D_user; /* XXX: Correct? */
503 markdata->md_window = fore;
504 markdata->second = 0;
505 markdata->rep_cnt = 0;
506 markdata->append_mode = 0;
507 markdata->write_buffer = 0;
508 markdata->nonl = 0;
509 markdata->left_mar = 0;
510 markdata->right_mar = fore->w_width - 1;
511 markdata->hist_offset = fore->w_histheight;
512 x = fore->w_x;
513 y = D2W(fore->w_y);
514 if (x >= fore->w_width)
515 x = fore->w_width - 1;
517 LGotoPos(flayer, x, W2D(y));
518 LMsg(0, "Copy mode - Column %d Line %d(+%d) (%d,%d)",
519 x + 1, W2D(y + 1), fore->w_histheight, fore->w_width, fore->w_height);
520 markdata->cx = markdata->x1 = x;
521 markdata->cy = markdata->y1 = y;
522 flayer->l_x = x;
523 flayer->l_y = W2D(y);
526 static void
527 MarkProcess(inbufp,inlenp)
528 char **inbufp;
529 int *inlenp;
531 char *inbuf, *pt;
532 int inlen;
533 int cx, cy, x2, y2, j, yend;
534 int newcopylen = 0, od;
535 int in_mark;
536 int rep_cnt;
537 struct acluser *md_user;
540 char *extrap = 0, extrabuf[100];
543 markdata = (struct markdata *)flayer->l_data;
544 fore = markdata->md_window;
545 md_user = markdata->md_user;
546 if (inbufp == 0)
548 MarkAbort();
549 return;
552 LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
553 inbuf= *inbufp;
554 inlen= *inlenp;
555 pt = inbuf;
556 in_mark = 1;
557 while (in_mark && (inlen /* || extrap */))
560 if (extrap)
562 od = *extrap++;
563 if (*extrap == 0)
564 extrap = 0;
566 else
569 od = mark_key_tab[(int)(unsigned char)*pt++];
570 inlen--;
572 rep_cnt = markdata->rep_cnt;
573 if (od >= '0' && od <= '9' && !markdata->f_cmd.flag)
575 if (rep_cnt < 1001 && (od != '0' || rep_cnt != 0))
577 markdata->rep_cnt = 10 * rep_cnt + od - '0';
578 continue;
580 * Now what is that 1001 here? Well, we have a screen with
581 * 25 * 80 = 2000 characters. Movement is at most across the full
582 * screen. This we do with word by word movement, as character by
583 * character movement never steps over line boundaries. The most words
584 * we can place on the screen are 1000 single letter words. Thus 1001
585 * is sufficient. Users with bigger screens never write in single letter
586 * words, as they should be more advanced. jw.
587 * Oh, wrong. We still give even the experienced user a factor of ten.
591 cx = markdata->cx;
592 cy = markdata->cy;
594 if (markdata -> f_cmd.flag) {
595 debug2("searching for %c:%d\n",od,rep_cnt);
596 markdata->f_cmd.flag = 0;
597 markdata->rep_cnt = 0;
599 if (isgraph (od)) {
600 markdata->f_cmd.target = od;
601 rep_cnt = (rep_cnt) ? rep_cnt : 1;
602 nextchar(&cx, &cy, markdata->f_cmd.direction, od, rep_cnt );
603 revto(cx, cy);
604 continue;
608 switch (od)
610 case 'f': /* fall through */
611 case 'F': /* fall through */
612 case 't': /* fall through */
613 case 'T': /* fall through */
615 * Set f_cmd to do a search on the next key stroke.
616 * If we break, rep_cnt will be reset, so we
617 * continue instead. It might be cleaner to
618 * store the rep_count in f_cmd and
619 * break here so later followon code will be
620 * hit.
622 markdata->f_cmd.flag = 1;
623 markdata->f_cmd.direction = od;
624 debug("entering char search\n");
625 continue;
626 case ';':
627 if (!markdata->f_cmd.target)
628 break;
629 if (!rep_cnt)
630 rep_cnt = 1;
631 nextchar(&cx, &cy, markdata->f_cmd.direction, markdata->f_cmd.target, rep_cnt );
632 revto(cx, cy);
633 break;
634 case ',': {
635 int search_dir;
636 if (!markdata->f_cmd.target)
637 break;
638 if (!rep_cnt)
639 rep_cnt = 1;
640 switch (markdata->f_cmd.direction) {
641 case 't': search_dir = 'T'; break;
642 case 'T': search_dir = 't'; break;
643 case 'f': search_dir = 'F'; break;
644 case 'F': search_dir = 'f'; break;
646 nextchar(&cx, &cy, search_dir, markdata->f_cmd.target, rep_cnt );
647 revto(cx, cy);
648 break;
651 case 'o':
652 case 'x':
653 if (!markdata->second)
654 break;
655 markdata->cx = markdata->x1;
656 markdata->cy = markdata->y1;
657 markdata->x1 = cx;
658 markdata->y1 = cy;
659 revto(markdata->cx, markdata->cy);
660 break;
661 case '\014': /* CTRL-L Redisplay */
662 Redisplay(0);
663 LGotoPos(flayer, cx, W2D(cy));
664 break;
665 case 0202: /* M-C-b */
666 case '\010': /* CTRL-H Backspace */
667 case 'h':
668 if (rep_cnt == 0)
669 rep_cnt = 1;
670 revto(cx - rep_cnt, cy);
671 break;
672 case 0216: /* M-C-p */
673 case '\016': /* CTRL-N */
674 case 'j':
675 if (rep_cnt == 0)
676 rep_cnt = 1;
677 revto(cx, cy + rep_cnt);
678 break;
679 case '+':
680 if (rep_cnt == 0)
681 rep_cnt = 1;
682 j = cy + rep_cnt;
683 if (j > fore->w_histheight + fore->w_height - 1)
684 j = fore->w_histheight + fore->w_height - 1;
685 revto(linestart(j), j);
686 break;
687 case '-':
688 if (rep_cnt == 0)
689 rep_cnt = 1;
690 cy -= rep_cnt;
691 if (cy < 0)
692 cy = 0;
693 revto(linestart(cy), cy);
694 break;
695 case '^':
696 revto(linestart(cy), cy);
697 break;
698 case '\n':
699 revto(markdata->left_mar, cy + 1);
700 break;
701 case 0220: /* M-C-p */
702 case '\020': /* CTRL-P */
703 case 'k':
704 if (rep_cnt == 0)
705 rep_cnt = 1;
706 revto(cx, cy - rep_cnt);
707 break;
708 case 0206: /* M-C-f */
709 case 'l':
710 if (rep_cnt == 0)
711 rep_cnt = 1;
712 revto(cx + rep_cnt, cy);
713 break;
714 case '\001': /* CTRL-A from tcsh/emacs */
715 case '0':
716 revto(markdata->left_mar, cy);
717 break;
718 case '\004': /* CTRL-D down half screen */
719 if (rep_cnt == 0)
720 rep_cnt = (fore->w_height + 1) >> 1;
721 revto_line(cx, cy + rep_cnt, W2D(cy));
722 break;
723 case '$':
724 revto(lineend(cy), cy);
725 break;
726 case '\022': /* CTRL-R emacs style backwards search */
727 ISearch(-1);
728 in_mark = 0;
729 break;
730 case '\023': /* CTRL-S emacs style search */
731 ISearch(1);
732 in_mark = 0;
733 break;
734 case '\025': /* CTRL-U up half screen */
735 if (rep_cnt == 0)
736 rep_cnt = (fore->w_height + 1) >> 1;
737 revto_line(cx, cy - rep_cnt, W2D(cy));
738 break;
739 case '\007': /* CTRL-G show cursorpos */
740 if (markdata->left_mar == 0 && markdata->right_mar == fore->w_width - 1)
741 LMsg(0, "Column %d Line %d(+%d)", cx+1, W2D(cy)+1,
742 markdata->hist_offset);
743 else
744 LMsg(0, "Column %d(%d..%d) Line %d(+%d)", cx+1,
745 markdata->left_mar+1, markdata->right_mar+1, W2D(cy)+1, markdata->hist_offset);
746 break;
747 case '\002': /* CTRL-B back 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 '\006': /* CTRL-F forward one page */
754 if (rep_cnt == 0)
755 rep_cnt = 1;
756 rep_cnt *= fore->w_height;
757 revto(cx, cy + rep_cnt);
758 break;
759 case '\005': /* CTRL-E scroll up */
760 if (rep_cnt == 0)
761 rep_cnt = 1;
762 rep_cnt = MarkScrollUpDisplay(rep_cnt);
763 if (cy < D2W(0))
764 revto(cx, D2W(0));
765 else
766 LGotoPos(flayer, cx, W2D(cy));
767 break;
768 case '\031': /* CTRL-Y scroll down */
769 if (rep_cnt == 0)
770 rep_cnt = 1;
771 rep_cnt = MarkScrollDownDisplay(rep_cnt);
772 if (cy > D2W(fore->w_height-1))
773 revto(cx, D2W(fore->w_height-1));
774 else
775 LGotoPos(flayer, cx, W2D(cy));
776 break;
777 case '@':
778 /* it may be usefull to have a key that does nothing */
779 break;
780 case '%':
781 rep_cnt--;
782 /* rep_cnt is a percentage for the history buffer */
783 if (rep_cnt < 0)
784 rep_cnt = 0;
785 if (rep_cnt > 100)
786 rep_cnt = 100;
787 revto_line(markdata->left_mar, (rep_cnt * (fore->w_histheight + fore->w_height)) / 100, (fore->w_height - 1) / 2);
788 break;
789 case 0201:
790 case 'g':
791 rep_cnt = 1;
792 /* FALLTHROUGH */
793 case 0205:
794 case 'G':
795 /* rep_cnt is here the WIN line number */
796 if (rep_cnt == 0)
797 rep_cnt = fore->w_histheight + fore->w_height;
798 revto_line(markdata->left_mar, --rep_cnt, (fore->w_height - 1) / 2);
799 break;
800 case 'H':
801 revto(markdata->left_mar, D2W(0));
802 break;
803 case 'M':
804 revto(markdata->left_mar, D2W((fore->w_height - 1) / 2));
805 break;
806 case 'L':
807 revto(markdata->left_mar, D2W(fore->w_height - 1));
808 break;
809 case '|':
810 revto(--rep_cnt, cy);
811 break;
812 case 'w':
813 if (rep_cnt == 0)
814 rep_cnt = 1;
815 nextword(&cx, &cy, NW_MUSTMOVE, rep_cnt);
816 revto(cx, cy);
817 break;
818 case 'e':
819 case 'E':
820 if (rep_cnt == 0)
821 rep_cnt = 1;
822 nextword(&cx, &cy, NW_ENDOFWORD|NW_MUSTMOVE | (od == 'E' ? NW_BIG : 0), rep_cnt);
823 revto(cx, cy);
824 break;
825 case 'b':
826 case 'B':
827 if (rep_cnt == 0)
828 rep_cnt = 1;
829 nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD|NW_MUSTMOVE | (od == 'B' ? NW_BIG : 0), rep_cnt);
830 revto(cx, cy);
831 break;
832 case 'a':
833 markdata->append_mode = 1 - markdata->append_mode;
834 debug1("append mode %d--\n", markdata->append_mode);
835 LMsg(0, (markdata->append_mode) ? ":set append" : ":set noappend");
836 break;
837 case 'v':
838 case 'V':
839 /* this sets start column to column 9 for VI :set nu users */
840 if (markdata->left_mar == 8)
841 rep_cnt = 1;
842 else
843 rep_cnt = 9;
844 /* FALLTHROUGH */
845 case 'c':
846 case 'C':
847 /* set start column (c) and end column (C) */
848 if (markdata->second)
850 rem(markdata->x1, markdata->y1, cx, cy, 1, (char *)0, fore->w_height-1); /* Hack */
851 markdata->second = 1; /* rem turns off second */
853 rep_cnt--;
854 if (rep_cnt < 0)
855 rep_cnt = cx;
856 if (od != 'C')
858 markdata->left_mar = rep_cnt;
859 if (markdata->left_mar > markdata->right_mar)
860 markdata->left_mar = markdata->right_mar;
862 else
864 markdata->right_mar = rep_cnt;
865 if (markdata->left_mar > markdata->right_mar)
866 markdata->right_mar = markdata->left_mar;
868 if (markdata->second)
870 markdata->cx = markdata->x1; markdata->cy = markdata->y1;
871 revto(cx, cy);
873 if (od == 'v' || od == 'V')
874 LMsg(0, (markdata->left_mar != 8) ? ":set nonu" : ":set nu");
875 break;
876 case 'J':
877 /* how do you join lines in VI ? */
878 markdata->nonl = (markdata->nonl + 1) % 4;
879 switch (markdata->nonl)
881 case 0:
882 if (join_with_cr)
883 LMsg(0, "Multiple lines (CR/LF)");
884 else
885 LMsg(0, "Multiple lines (LF)");
886 break;
887 case 1:
888 LMsg(0, "Lines joined");
889 break;
890 case 2:
891 LMsg(0, "Lines joined with blanks");
892 break;
893 case 3:
894 LMsg(0, "Lines joined with comma");
895 break;
897 break;
898 case '/':
899 Search(1);
900 in_mark = 0;
901 break;
902 case '?':
903 Search(-1);
904 in_mark = 0;
905 break;
906 case 'n':
907 Search(0);
908 break;
909 case 'N':
910 markdata->isdir = -markdata->isdir;
911 Search(0);
912 markdata->isdir = -markdata->isdir;
913 break;
914 case 'y':
915 case 'Y':
916 if (markdata->second == 0)
918 revto(linestart(cy), cy);
919 markdata->second++;
920 cx = markdata->x1 = markdata->cx;
921 cy = markdata->y1 = markdata->cy;
923 if (--rep_cnt > 0)
924 revto(cx, cy + rep_cnt);
925 revto(lineend(markdata->cy), markdata->cy);
926 if (od == 'y')
927 break;
928 /* FALLTHROUGH */
929 case 'W':
930 if (od == 'W')
932 if (rep_cnt == 0)
933 rep_cnt = 1;
934 if (!markdata->second)
936 nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD, 1);
937 revto(cx, cy);
938 markdata->second++;
939 cx = markdata->x1 = markdata->cx;
940 cy = markdata->y1 = markdata->cy;
942 nextword(&cx, &cy, NW_ENDOFWORD, rep_cnt);
943 revto(cx, cy);
945 cx = markdata->cx;
946 cy = markdata->cy;
947 /* FALLTHROUGH */
948 case 'A':
949 if (od == 'A')
950 markdata->append_mode = 1;
951 /* FALLTHROUGH */
952 case '>':
953 if (od == '>')
954 markdata->write_buffer = 1;
955 /* FALLTHROUGH */
956 case ' ':
957 case '\r':
958 if (!markdata->second)
960 markdata->second++;
961 markdata->x1 = cx;
962 markdata->y1 = cy;
963 revto(cx, cy);
964 LMsg(0, "First mark set - Column %d Line %d", cx+1, W2D(cy)+1);
965 break;
967 else
969 int append_mode = markdata->append_mode;
970 int write_buffer = markdata->write_buffer;
972 x2 = cx;
973 y2 = cy;
974 newcopylen = rem(markdata->x1, markdata->y1, x2, y2, 2, (char *)0, 0); /* count */
975 if (md_user->u_plop.buf && !append_mode)
976 UserFreeCopyBuffer(md_user);
977 yend = fore->w_height - 1;
978 if (fore->w_histheight - markdata->hist_offset < fore->w_height)
980 markdata->second = 0;
981 yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
983 if (newcopylen > 0)
985 /* the +3 below is for : cr + lf + \0 */
986 if (md_user->u_plop.buf)
987 md_user->u_plop.buf = realloc(md_user->u_plop.buf,
988 (unsigned) (md_user->u_plop.len + newcopylen + 3));
989 else
991 md_user->u_plop.len = 0;
992 md_user->u_plop.buf = malloc((unsigned) (newcopylen + 3));
994 if (!md_user->u_plop.buf)
996 MarkAbort();
997 in_mark = 0;
998 LMsg(0, "Not enough memory... Sorry.");
999 md_user->u_plop.len = 0;
1000 md_user->u_plop.buf = 0;
1001 break;
1003 if (append_mode)
1005 switch (markdata->nonl)
1008 * this code defines, what glues lines together
1010 case 0:
1011 if (join_with_cr)
1013 md_user->u_plop.buf[md_user->u_plop.len] = '\r';
1014 md_user->u_plop.len++;
1016 md_user->u_plop.buf[md_user->u_plop.len] = '\n';
1017 md_user->u_plop.len++;
1018 break;
1019 case 1:
1020 break;
1021 case 2:
1022 md_user->u_plop.buf[md_user->u_plop.len] = ' ';
1023 md_user->u_plop.len++;
1024 break;
1025 case 3:
1026 md_user->u_plop.buf[md_user->u_plop.len] = ',';
1027 md_user->u_plop.len++;
1028 break;
1031 md_user->u_plop.len += rem(markdata->x1, markdata->y1, x2, y2,
1032 markdata->hist_offset == fore->w_histheight,
1033 md_user->u_plop.buf + md_user->u_plop.len, yend);
1034 #ifdef ENCODINGS
1035 md_user->u_plop.enc = fore->w_encoding;
1036 #endif
1038 if (markdata->hist_offset != fore->w_histheight)
1040 LAY_CALL_UP(LRefreshAll(flayer, 0));
1042 ExitOverlayPage();
1043 if (append_mode)
1044 LMsg(0, "Appended %d characters to buffer",
1045 newcopylen);
1046 else
1047 LMsg(0, "Copied %d characters into buffer", md_user->u_plop.len);
1048 if (write_buffer)
1049 WriteFile(md_user, (char *)0, DUMP_EXCHANGE);
1050 in_mark = 0;
1051 break;
1053 default:
1054 MarkAbort();
1055 LMsg(0, "Copy mode aborted");
1056 in_mark = 0;
1057 break;
1059 if (in_mark) /* markdata may be freed */
1060 markdata->rep_cnt = 0;
1062 if (in_mark)
1064 flayer->l_x = markdata->cx;
1065 flayer->l_y = W2D(markdata->cy);
1067 *inbufp = pt;
1068 *inlenp = inlen;
1071 void revto(tx, ty)
1072 int tx, ty;
1074 revto_line(tx, ty, -1);
1077 /* tx, ty: WINDOW, line: DISPLAY */
1078 void revto_line(tx, ty, line)
1079 int tx, ty, line;
1081 int fx, fy;
1082 int x, y, t, revst, reven, qq, ff, tt, st, en, ce = 0;
1083 int ystart = 0, yend = fore->w_height-1;
1084 int i, ry;
1085 unsigned char *wi;
1086 struct mline *ml;
1087 struct mchar mc;
1089 if (tx < 0)
1090 tx = 0;
1091 else if (tx > fore->w_width - 1)
1092 tx = fore->w_width -1;
1093 if (ty < 0)
1094 ty = 0;
1095 else if (ty > fore->w_histheight + fore->w_height - 1)
1096 ty = fore->w_histheight + fore->w_height - 1;
1098 fx = markdata->cx; fy = markdata->cy;
1100 #ifdef DW_CHARS
1101 /* don't just move inside of a kanji, the user wants to see something */
1102 ml = WIN(ty);
1103 if (ty == fy && fx + 1 == tx && dw_right(ml, tx, fore->w_encoding) && tx < D_width - 1)
1104 tx++;
1105 if (ty == fy && fx - 1 == tx && dw_right(ml, fx, fore->w_encoding) && tx)
1106 tx--;
1107 #endif
1109 markdata->cx = tx; markdata->cy = ty;
1112 * if we go to a position that is currently offscreen
1113 * then scroll the screen
1115 i = 0;
1116 if (line >= 0 && line < fore->w_height)
1117 i = W2D(ty) - line;
1118 else if (ty < markdata->hist_offset)
1119 i = ty - markdata->hist_offset;
1120 else if (ty > markdata->hist_offset + (fore->w_height - 1))
1121 i = ty - markdata->hist_offset - (fore->w_height - 1);
1122 if (i > 0)
1123 yend -= MarkScrollUpDisplay(i);
1124 else if (i < 0)
1125 ystart += MarkScrollDownDisplay(-i);
1127 if (markdata->second == 0)
1129 LGotoPos(flayer, tx, W2D(ty));
1130 return;
1133 qq = markdata->x1 + markdata->y1 * fore->w_width;
1134 ff = fx + fy * fore->w_width; /* "from" offset in WIN coords */
1135 tt = tx + ty * fore->w_width; /* "to" offset in WIN coords*/
1137 if (ff > tt)
1139 st = tt; en = ff;
1140 x = tx; y = ty;
1142 else
1144 st = ff; en = tt;
1145 x = fx; y = fy;
1147 if (st > qq)
1149 st++;
1150 x++;
1152 if (en < qq)
1153 en--;
1154 if (tt > qq)
1156 revst = qq; reven = tt;
1158 else
1160 revst = tt; reven = qq;
1162 ry = y - markdata->hist_offset;
1163 if (ry < ystart)
1165 y += (ystart - ry);
1166 x = 0;
1167 st = y * fore->w_width;
1168 ry = ystart;
1170 ml = WIN(y);
1171 for (t = st; t <= en; t++, x++)
1173 if (x >= fore->w_width)
1175 x = 0;
1176 y++, ry++;
1177 ml = WIN(y);
1179 if (ry > yend)
1180 break;
1181 if (t == st || x == 0)
1183 wi = ml->image + fore->w_width;
1184 for (ce = fore->w_width; ce >= 0; ce--, wi--)
1185 if (*wi != ' ')
1186 break;
1188 if (x <= ce && x >= markdata->left_mar && x <= markdata->right_mar)
1190 #ifdef DW_CHARS
1191 if (dw_right(ml, x, fore->w_encoding))
1193 if (t == revst)
1194 revst--;
1195 t--;
1196 x--;
1198 #endif
1199 if (t >= revst && t <= reven)
1201 mc = mchar_so;
1202 #ifdef FONT
1203 if (pastefont)
1204 mc.font = ml->font[x];
1205 #endif
1206 mc.image = ml->image[x];
1208 else
1209 copy_mline2mchar(&mc, ml, x);
1210 #ifdef DW_CHARS
1211 if (dw_left(ml, x, fore->w_encoding))
1213 mc.mbcs = ml->image[x + 1];
1214 LPutChar(flayer, &mc, x, W2D(y));
1215 t++;
1217 #endif
1218 LPutChar(flayer, &mc, x, W2D(y));
1219 #ifdef DW_CHARS
1220 if (dw_left(ml, x, fore->w_encoding))
1221 x++;
1222 #endif
1225 LGotoPos(flayer, tx, W2D(ty));
1228 static void
1229 MarkAbort()
1231 int yend, redisp;
1233 debug("MarkAbort\n");
1234 markdata = (struct markdata *)flayer->l_data;
1235 fore = markdata->md_window;
1236 yend = fore->w_height - 1;
1237 redisp = markdata->second;
1238 if (fore->w_histheight - markdata->hist_offset < fore->w_height)
1240 markdata->second = 0;
1241 yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
1243 if (markdata->hist_offset != fore->w_histheight)
1245 LAY_CALL_UP(LRefreshAll(flayer, 0));
1247 else
1249 rem(markdata->x1, markdata->y1, markdata->cx, markdata->cy, redisp, (char *)0, yend);
1251 ExitOverlayPage();
1255 static void
1256 MarkRedisplayLine(y, xs, xe, isblank)
1257 int y; /* NOTE: y is in DISPLAY coords system! */
1258 int xs, xe;
1259 int isblank;
1261 int wy, x, i, rm;
1262 int sta, sto, cp; /* NOTE: these 3 are in WINDOW coords system */
1263 unsigned char *wi;
1264 struct mline *ml;
1265 struct mchar mchar_marked;
1267 if (y < 0) /* No special full page handling */
1268 return;
1270 markdata = (struct markdata *)flayer->l_data;
1271 fore = markdata->md_window;
1273 mchar_marked = mchar_so;
1275 wy = D2W(y);
1276 ml = WIN(wy);
1278 if (markdata->second == 0)
1280 if (dw_right(ml, xs, fore->w_encoding) && xs > 0)
1281 xs--;
1282 if (dw_left(ml, xe, fore->w_encoding) && xe < fore->w_width - 1)
1283 xe++;
1284 if (xs == 0 && y > 0 && wy > 0 && WIN(wy - 1)->image[flayer->l_width] == 0)
1285 LCDisplayLineWrap(flayer, ml, y, xs, xe, isblank);
1286 else
1287 LCDisplayLine(flayer, ml, y, xs, xe, isblank);
1288 return;
1291 sta = markdata->y1 * fore->w_width + markdata->x1;
1292 sto = markdata->cy * fore->w_width + markdata->cx;
1293 if (sta > sto)
1295 i=sta; sta=sto; sto=i;
1297 cp = wy * fore->w_width + xs;
1299 rm = markdata->right_mar;
1300 for (x = fore->w_width, wi = ml->image + fore->w_width; x >= 0; x--, wi--)
1301 if (*wi != ' ')
1302 break;
1303 if (x < rm)
1304 rm = x;
1306 for (x = xs; x <= xe; x++, cp++)
1307 if (cp >= sta && x >= markdata->left_mar)
1308 break;
1309 #ifdef DW_CHARS
1310 if (dw_right(ml, x, fore->w_encoding))
1311 x--;
1312 #endif
1313 if (x > xs)
1314 LCDisplayLine(flayer, ml, y, xs, x - 1, isblank);
1315 for (; x <= xe; x++, cp++)
1317 if (cp > sto || x > rm)
1318 break;
1319 #ifdef FONT
1320 if (pastefont)
1321 mchar_marked.font = ml->font[x];
1322 #endif
1323 mchar_marked.image = ml->image[x];
1324 #ifdef DW_CHARS
1325 mchar_marked.mbcs = 0;
1326 if (dw_left(ml, x, fore->w_encoding))
1328 mchar_marked.mbcs = ml->image[x + 1];
1329 cp++;
1331 #endif
1332 LPutChar(flayer, &mchar_marked, x, y);
1333 #ifdef DW_CHARS
1334 if (dw_left(ml, x, fore->w_encoding))
1335 x++;
1336 #endif
1338 if (x <= xe)
1339 LCDisplayLine(flayer, ml, y, x, xe, isblank);
1344 * This ugly routine is to speed up GotoPos()
1346 static int
1347 MarkRewrite(ry, xs, xe, rend, doit)
1348 int ry, xs, xe, doit;
1349 struct mchar *rend;
1351 int dx, x, y, st, en, t, rm;
1352 unsigned char *i;
1353 struct mline *ml;
1354 struct mchar mchar_marked;
1356 mchar_marked = mchar_so;
1358 debug3("MarkRewrite %d, %d-%d\n", ry, xs, xe);
1359 markdata = (struct markdata *)flayer->l_data;
1360 fore = markdata->md_window;
1361 y = D2W(ry);
1362 ml = WIN(y);
1363 #ifdef UTF8
1364 if (fore->w_encoding && fore->w_encoding != UTF8 && D_encoding == UTF8 && ContainsSpecialDeffont(ml, xs, xe, fore->w_encoding))
1365 return EXPENSIVE;
1366 #endif
1367 dx = xe - xs + 1;
1368 if (doit)
1370 i = ml->image + xs;
1371 while (dx--)
1372 PUTCHAR(*i++);
1373 return 0;
1376 if (markdata->second == 0)
1377 st = en = -1;
1378 else
1380 st = markdata->y1 * fore->w_width + markdata->x1;
1381 en = markdata->cy * fore->w_width + markdata->cx;
1382 if (st > en)
1384 t = st; st = en; en = t;
1387 t = y * fore->w_width + xs;
1388 for (rm = fore->w_width, i = ml->image + fore->w_width; rm >= 0; rm--)
1389 if (*i-- != ' ')
1390 break;
1391 if (rm > markdata->right_mar)
1392 rm = markdata->right_mar;
1393 x = xs;
1394 while (dx--)
1396 if (t >= st && t <= en && x >= markdata->left_mar && x <= rm)
1398 #ifdef FONT
1399 if (pastefont)
1400 mchar_marked.font = ml->font[x];
1401 #endif
1402 rend->image = mchar_marked.image;
1403 if (!cmp_mchar(rend, &mchar_marked))
1404 return EXPENSIVE;
1406 else
1408 rend->image = ml->image[x];
1409 if (!cmp_mchar_mline(rend, ml, x))
1410 return EXPENSIVE;
1412 x++;
1414 return xe - xs + 1;
1419 * scroll the screen contents up/down.
1421 static int MarkScrollUpDisplay(n)
1422 int n;
1424 int i;
1426 debug1("MarkScrollUpDisplay(%d)\n", n);
1427 if (n <= 0)
1428 return 0;
1429 if (n > fore->w_histheight - markdata->hist_offset)
1430 n = fore->w_histheight - markdata->hist_offset;
1431 markdata->hist_offset += n;
1432 i = (n < flayer->l_height) ? n : (flayer->l_height);
1433 LScrollV(flayer, i, 0, flayer->l_height - 1, 0);
1434 while (i-- > 0)
1435 MarkRedisplayLine(flayer->l_height - i - 1, 0, flayer->l_width - 1, 1);
1436 return n;
1439 static int
1440 MarkScrollDownDisplay(n)
1441 int n;
1443 int i;
1445 debug1("MarkScrollDownDisplay(%d)\n", n);
1446 if (n <= 0)
1447 return 0;
1448 if (n > markdata->hist_offset)
1449 n = markdata->hist_offset;
1450 markdata->hist_offset -= n;
1451 i = (n < flayer->l_height) ? n : (flayer->l_height);
1452 LScrollV(flayer, -i, 0, fore->w_height - 1, 0);
1453 while (i-- > 0)
1454 MarkRedisplayLine(i, 0, flayer->l_width - 1, 1);
1455 return n;
1459 InMark()
1461 if (flayer && flayer->l_layfn == &MarkLf)
1462 return 1;
1463 return 0;
1466 void
1467 MakePaster(pa, buf, len, bufiscopy)
1468 struct paster *pa;
1469 char *buf;
1470 int len;
1471 int bufiscopy;
1473 FreePaster(pa);
1474 pa->pa_pasteptr = buf;
1475 pa->pa_pastelen = len;
1476 if (bufiscopy)
1477 pa->pa_pastebuf = buf;
1478 pa->pa_pastelayer = flayer;
1479 DoProcess(Layer2Window(flayer), &pa->pa_pasteptr, &pa->pa_pastelen, pa);
1482 void
1483 FreePaster(pa)
1484 struct paster *pa;
1486 if (pa->pa_pastebuf)
1487 free(pa->pa_pastebuf);
1488 pa->pa_pastebuf = 0;
1489 pa->pa_pasteptr = 0;
1490 pa->pa_pastelen = 0;
1491 pa->pa_pastelayer = 0;
1492 evdeq(&pa->pa_slowev);
1495 #endif /* COPY_PASTE */