Bring back --with-sys-screenrc configure flag.
[screen-lua.git] / src / mark.c
blobccb74f9fea83c7a6a4ccf6d83bf04135bb609468
1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * 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,
84 int join_with_cr = 0;
85 int compacthist = 0;
87 unsigned char mark_key_tab[256]; /* this array must be initialised first! */
89 static struct markdata *markdata;
93 * VI like is_letter: 0 - whitespace
94 * 1 - letter
95 * 2 - other
97 static int is_letter(c)
98 char c;
100 if ((c >= 'a' && c <= 'z') ||
101 (c >= 'A' && c <= 'Z') ||
102 (c >= '0' && c <= '9') ||
103 c == '_' || c == '.' ||
104 c == '@' || c == ':' ||
105 c == '%' || c == '!' ||
106 c == '-' || c == '+')
107 /* thus we can catch email-addresses as a word :-) */
108 return 1;
109 else if (c != ' ')
110 return 2;
111 return 0;
114 static int
115 linestart(y)
116 int y;
118 register int x;
119 register unsigned char *i;
121 for (x = markdata->left_mar, i = WIN(y)->image + x; x < fore->w_width - 1; x++)
122 if (*i++ != ' ')
123 break;
124 if (x == fore->w_width - 1)
125 x = markdata->left_mar;
126 return x;
129 static int
130 lineend(y)
131 int y;
133 register int x;
134 register unsigned char *i;
136 for (x = markdata->right_mar, i = WIN(y)->image + x; x >= 0; x--)
137 if (*i-- != ' ')
138 break;
139 if (x < 0)
140 x = markdata->left_mar;
141 return x;
145 * nextchar sets *xp to the num-th occurrence of the target in the line.
147 * Returns -1 if the target doesn't appear num times, 0 otherwise.
149 static int
150 nextchar(int *xp, int *yp, int direction, char target, int num)
152 int width; /* width of the current window. */
153 int x; /* x coordinate of the current cursor position. */
154 int step; /* amount to increment x (+1 or -1) */
155 int adjust; /* Final adjustment of cursor position. */
156 char *displayed_line; /* Line in which search takes place. */
158 debug("nextchar\n");
160 x = *xp;
161 adjust = 0;
162 width = fore->w_width;
163 displayed_line = (char *)WIN(*yp) -> image;
165 switch(direction) {
166 case 't':
167 adjust = -1; /* fall through */
168 case 'f':
169 step = 1;
170 break;
171 case 'T':
172 adjust = 1; /* fall through */
173 case 'F':
174 step = -1;
175 break;
176 default:
177 ASSERT(0);
180 x += step;
182 debug1("ml->image = %s\n", displayed_line);
183 debug2("num = %d, width = %d\n",num, width);
184 debug2("x = %d target = %c\n", x, target );
186 for ( ;x>=0 && x <= width; x += step) {
187 if (displayed_line[x] == target) {
188 if (--num == 0) {
189 *xp = x + adjust;
190 return 0;
194 return -1;
198 * nextword calculates the cursor position of the num'th word.
199 * If the cursor is on a word, it counts as the first.
200 * NW_BACK: search backward
201 * NW_ENDOFWORD: find the end of the word
202 * NW_MUSTMOVE: move at least one char
203 * NW_BIG: match WORDs not words
206 #define NW_BACK (1<<0)
207 #define NW_ENDOFWORD (1<<1)
208 #define NW_MUSTMOVE (1<<2)
209 #define NW_BIG (1<<3)
213 static void
214 nextword(xp, yp, flags, num)
215 int *xp, *yp, flags, num;
217 int xx = fore->w_width, yy = fore->w_histheight + fore->w_height;
218 register int sx, oq, q, x, y;
219 struct mline *ml;
221 x = *xp;
222 y = *yp;
223 sx = (flags & NW_BACK) ? -1 : 1;
224 if ((flags & NW_ENDOFWORD) && (flags & NW_MUSTMOVE))
225 x += sx;
226 ml = WIN(y);
227 for (oq = -1; ; x += sx, oq = q)
229 if (x >= xx || x < 0)
230 q = 0;
231 else if (flags & NW_BIG)
232 q = ml->image[x] == ' ';
233 else
234 q = is_letter(ml->image[x]);
235 if (oq >= 0 && oq != q)
237 if (oq == 0 || !(flags & NW_ENDOFWORD))
238 *xp = x;
239 else
240 *xp = x-sx;
241 *yp = y;
242 if ((!(flags & NW_ENDOFWORD) && q) ||
243 ((flags & NW_ENDOFWORD) && oq))
245 if (--num <= 0)
246 return;
249 if (x == xx)
251 x = -1;
252 if (++y >= yy)
253 return;
254 ml = WIN(y);
256 else if (x < 0)
258 x = xx;
259 if (--y < 0)
260 return;
261 ml = WIN(y);
268 * y1, y2 are WIN coordinates
270 * redisplay: 0 - just copy
271 * 1 - redisplay + copy
272 * 2 - count + copy, don't redisplay
275 static int
276 rem(x1, y1, x2, y2, redisplay, pt, yend)
277 int x1, y1, x2, y2, redisplay, yend;
278 char *pt;
280 int i, j, from, to, ry, c;
281 int l = 0;
282 unsigned char *im;
283 struct mline *ml;
284 #ifdef FONT
285 int cf, font;
286 unsigned char *fo;
287 #endif
289 markdata->second = 0;
290 if (y2 < y1 || ((y2 == y1) && (x2 < x1)))
292 i = y2;
293 y2 = y1;
294 y1 = i;
295 i = x2;
296 x2 = x1;
297 x1 = i;
299 ry = y1 - markdata->hist_offset;
301 i = y1;
302 if (redisplay != 2 && pt == 0 && ry <0)
304 i -= ry;
305 ry = 0;
307 for (; i <= y2; i++, ry++)
309 if (redisplay != 2 && pt == 0 && ry > yend)
310 break;
311 ml = WIN(i);
312 from = (i == y1) ? x1 : 0;
313 if (from < markdata->left_mar)
314 from = markdata->left_mar;
315 for (to = fore->w_width, im = ml->image + to; to >= 0; to--)
316 if (*im-- != ' ')
317 break;
318 if (i == y2 && x2 < to)
319 to = x2;
320 if (to > markdata->right_mar)
321 to = markdata->right_mar;
322 if (redisplay == 1 && from <= to && ry >=0 && ry <= yend)
323 MarkRedisplayLine(ry, from, to, 0);
324 if (redisplay != 2 && pt == 0) /* don't count/copy */
325 continue;
326 j = from;
327 #ifdef DW_CHARS
328 if (dw_right(ml, j, fore->w_encoding))
329 j--;
330 #endif
331 im = ml->image + j;
332 #ifdef FONT
333 fo = ml->font + j;
334 font = ASCII;
335 #endif
336 for (; j <= to; j++)
338 c = (unsigned char)*im++;
339 #ifdef FONT
340 cf = (unsigned char)*fo++;
341 # ifdef UTF8
342 if (fore->w_encoding == UTF8)
344 c |= cf << 8;
345 if (c == UCS_HIDDEN)
346 continue;
347 c = ToUtf8_comb(pt, c);
348 l += c;
349 if (pt)
350 pt += c;
351 continue;
353 # endif
354 # ifdef DW_CHARS
355 if (is_dw_font(cf))
357 c = c << 8 | (unsigned char)*im++;
358 fo++;
359 j++;
361 # endif
362 if (pastefont)
364 c = EncodeChar(pt, c | cf << 16, fore->w_encoding, &font);
365 l += c;
366 if (pt)
367 pt += c;
368 continue;
370 #endif /* FONT */
371 if (pt)
372 *pt++ = c;
373 l++;
375 #ifdef FONT
376 if (pastefont && font != ASCII)
378 if (pt)
380 strcpy(pt, "\033(B");
381 pt += 3;
383 l += 3;
385 #endif
386 if (i != y2 && (to != fore->w_width - 1 || ml->image[to + 1] == ' '))
389 * this code defines, what glues lines together
391 switch (markdata->nonl)
393 case 0: /* lines separated by newlines */
394 if (pt)
395 *pt++ = '\r';
396 l++;
397 if (join_with_cr)
399 if (pt)
400 *pt++ = '\n';
401 l++;
403 break;
404 case 1: /* nothing to separate lines */
405 break;
406 case 2: /* lines separated by blanks */
407 if (pt)
408 *pt++ = ' ';
409 l++;
410 break;
411 case 3: /* seperate by comma, for csh junkies */
412 if (pt)
413 *pt++ = ',';
414 l++;
415 break;
419 return l;
422 /* Check if two chars are identical. All digits are treated
423 * as same. Used for GetHistory()
426 static int
427 eq(a, b)
428 int a, b;
430 if (a == b)
431 return 1;
432 if (a == 0 || b == 0)
433 return 1;
434 if (a <= '9' && a >= '0' && b <= '9' && b >= '0')
435 return 1;
436 return 0;
440 /**********************************************************************/
443 GetHistory() /* return value 1 if copybuffer changed */
445 int i = 0, q = 0, xx, yy, x, y;
446 unsigned char *linep;
447 struct mline *ml;
449 ASSERT(display && fore);
450 x = fore->w_x;
451 if (x >= fore->w_width)
452 x = fore->w_width - 1;
453 y = fore->w_y + fore->w_histheight;
454 debug2("cursor is at x=%d, y=%d\n", x, y);
455 ml = WIN(y);
456 for (xx = x - 1, linep = ml->image + xx; xx >= 0; xx--)
457 if ((q = *linep--) != ' ' )
458 break;
459 debug3("%c at (%d,%d)\n", q, xx, y);
460 for (yy = y - 1; yy >= 0; yy--)
462 ml = WIN(yy);
463 linep = ml->image;
464 if (xx < 0 || eq(linep[xx], q))
465 { /* line is matching... */
466 for (i = fore->w_width - 1, linep += i; i >= x; i--)
467 if (*linep-- != ' ')
468 break;
469 if (i >= x)
470 break;
473 if (yy < 0)
474 return 0;
475 if (D_user->u_plop.buf)
476 UserFreeCopyBuffer(D_user);
477 if ((D_user->u_plop.buf = (char *)malloc((unsigned) (i - x + 2))) == NULL)
479 LMsg(0, "Not enough memory... Sorry.");
480 return 0;
482 bcopy((char *)linep - i + x + 1, D_user->u_plop.buf, i - x + 1);
483 D_user->u_plop.len = i - x + 1;
484 #ifdef ENCODINGS
485 D_user->u_plop.enc = fore->w_encoding;
486 #endif
487 return 1;
490 /**********************************************************************/
493 void
494 MarkRoutine()
496 int x, y;
498 ASSERT(fore && display && D_user);
500 debug2("MarkRoutine called: fore nr %d, display %s\n",
501 fore->w_number, D_usertty);
503 if (InitOverlayPage(sizeof(*markdata), &MarkLf, 1))
504 return;
505 flayer->l_encoding = fore->w_encoding;
506 flayer->l_mode = 1;
507 markdata = (struct markdata *)flayer->l_data;
508 markdata->md_user = D_user; /* XXX: Correct? */
509 markdata->md_window = fore;
510 markdata->second = 0;
511 markdata->rep_cnt = 0;
512 markdata->append_mode = 0;
513 markdata->write_buffer = 0;
514 markdata->nonl = 0;
515 markdata->left_mar = 0;
516 markdata->right_mar = fore->w_width - 1;
517 markdata->hist_offset = fore->w_histheight;
518 x = fore->w_x;
519 y = D2W(fore->w_y);
520 if (x >= fore->w_width)
521 x = fore->w_width - 1;
523 LGotoPos(flayer, x, W2D(y));
524 LMsg(0, "Copy mode - Column %d Line %d(+%d) (%d,%d)",
525 x + 1, W2D(y + 1), fore->w_histheight, fore->w_width, fore->w_height);
526 markdata->cx = markdata->x1 = x;
527 markdata->cy = markdata->y1 = y;
528 flayer->l_x = x;
529 flayer->l_y = W2D(y);
532 static void
533 MarkProcess(inbufp,inlenp)
534 char **inbufp;
535 int *inlenp;
537 char *inbuf, *pt;
538 int inlen;
539 int cx, cy, x2, y2, j, yend;
540 int newcopylen = 0, od;
541 int in_mark;
542 int rep_cnt;
543 struct acluser *md_user;
546 char *extrap = 0, extrabuf[100];
549 markdata = (struct markdata *)flayer->l_data;
550 fore = markdata->md_window;
551 md_user = markdata->md_user;
552 if (inbufp == 0)
554 MarkAbort();
555 return;
558 LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
559 inbuf= *inbufp;
560 inlen= *inlenp;
561 pt = inbuf;
562 in_mark = 1;
563 while (in_mark && (inlen /* || extrap */))
565 unsigned char ch = (unsigned char )*pt++;
566 inlen--;
567 if (flayer->l_mouseevent.start)
569 int r = LayProcessMouse(flayer, ch);
570 if (r == -1)
571 LayProcessMouseSwitch(flayer, 0);
572 else
574 if (r)
575 ch = 0222;
576 else
577 continue;
580 od = mark_key_tab[(int)ch];
581 rep_cnt = markdata->rep_cnt;
582 if (od >= '0' && od <= '9' && !markdata->f_cmd.flag)
584 if (rep_cnt < 1001 && (od != '0' || rep_cnt != 0))
586 markdata->rep_cnt = 10 * rep_cnt + od - '0';
587 continue;
589 * Now what is that 1001 here? Well, we have a screen with
590 * 25 * 80 = 2000 characters. Movement is at most across the full
591 * screen. This we do with word by word movement, as character by
592 * character movement never steps over line boundaries. The most words
593 * we can place on the screen are 1000 single letter words. Thus 1001
594 * is sufficient. Users with bigger screens never write in single letter
595 * words, as they should be more advanced. jw.
596 * Oh, wrong. We still give even the experienced user a factor of ten.
600 cx = markdata->cx;
601 cy = markdata->cy;
603 if (markdata -> f_cmd.flag) {
604 debug2("searching for %c:%d\n",od,rep_cnt);
605 markdata->f_cmd.flag = 0;
606 markdata->rep_cnt = 0;
608 if (isgraph (od)) {
609 markdata->f_cmd.target = od;
610 rep_cnt = (rep_cnt) ? rep_cnt : 1;
611 nextchar(&cx, &cy, markdata->f_cmd.direction, od, rep_cnt );
612 revto(cx, cy);
613 continue;
617 processchar:
618 switch (od)
620 case 'f': /* fall through */
621 case 'F': /* fall through */
622 case 't': /* fall through */
623 case 'T': /* fall through */
625 * Set f_cmd to do a search on the next key stroke.
626 * If we break, rep_cnt will be reset, so we
627 * continue instead. It might be cleaner to
628 * store the rep_count in f_cmd and
629 * break here so later followon code will be
630 * hit.
632 markdata->f_cmd.flag = 1;
633 markdata->f_cmd.direction = od;
634 debug("entering char search\n");
635 continue;
636 case ';':
637 case ',':
638 if (!markdata->f_cmd.target)
639 break;
640 if (!rep_cnt)
641 rep_cnt = 1;
642 nextchar(&cx, &cy,
643 od == ';' ? markdata->f_cmd.direction : (markdata->f_cmd.direction ^ 0x20),
644 markdata->f_cmd.target, rep_cnt );
645 revto(cx, cy);
646 break;
647 case 'o':
648 case 'x':
649 if (!markdata->second)
650 break;
651 markdata->cx = markdata->x1;
652 markdata->cy = markdata->y1;
653 markdata->x1 = cx;
654 markdata->y1 = cy;
655 revto(markdata->cx, markdata->cy);
656 break;
657 case '\014': /* CTRL-L Redisplay */
658 Redisplay(0);
659 LGotoPos(flayer, cx, W2D(cy));
660 break;
661 case 0202: /* M-C-b */
662 case '\010': /* CTRL-H Backspace */
663 case 'h':
664 if (rep_cnt == 0)
665 rep_cnt = 1;
666 revto(cx - rep_cnt, cy);
667 break;
668 case 0216: /* M-C-p */
669 case '\016': /* CTRL-N */
670 case 'j':
671 if (rep_cnt == 0)
672 rep_cnt = 1;
673 revto(cx, cy + rep_cnt);
674 break;
675 case '+':
676 if (rep_cnt == 0)
677 rep_cnt = 1;
678 j = cy + rep_cnt;
679 if (j > fore->w_histheight + fore->w_height - 1)
680 j = fore->w_histheight + fore->w_height - 1;
681 revto(linestart(j), j);
682 break;
683 case '-':
684 if (rep_cnt == 0)
685 rep_cnt = 1;
686 cy -= rep_cnt;
687 if (cy < 0)
688 cy = 0;
689 revto(linestart(cy), cy);
690 break;
691 case '^':
692 revto(linestart(cy), cy);
693 break;
694 case '\n':
695 revto(markdata->left_mar, cy + 1);
696 break;
697 case 0220: /* M-C-p */
698 case '\020': /* CTRL-P */
699 case 'k':
700 if (rep_cnt == 0)
701 rep_cnt = 1;
702 revto(cx, cy - rep_cnt);
703 break;
704 case 0206: /* M-C-f */
705 case 'l':
706 if (rep_cnt == 0)
707 rep_cnt = 1;
708 revto(cx + rep_cnt, cy);
709 break;
710 case '\001': /* CTRL-A from tcsh/emacs */
711 case '0':
712 revto(markdata->left_mar, cy);
713 break;
714 case '\004': /* CTRL-D down half screen */
715 if (rep_cnt == 0)
716 rep_cnt = (fore->w_height + 1) >> 1;
717 revto_line(cx, cy + rep_cnt, W2D(cy));
718 break;
719 case '$':
720 revto(lineend(cy), cy);
721 break;
722 case '\022': /* CTRL-R emacs style backwards search */
723 ISearch(-1);
724 in_mark = 0;
725 break;
726 case '\023': /* CTRL-S emacs style search */
727 ISearch(1);
728 in_mark = 0;
729 break;
730 case '\025': /* CTRL-U up half screen */
731 if (rep_cnt == 0)
732 rep_cnt = (fore->w_height + 1) >> 1;
733 revto_line(cx, cy - rep_cnt, W2D(cy));
734 break;
735 case '\007': /* CTRL-G show cursorpos */
736 if (markdata->left_mar == 0 && markdata->right_mar == fore->w_width - 1)
737 LMsg(0, "Column %d Line %d(+%d)", cx+1, W2D(cy)+1,
738 markdata->hist_offset);
739 else
740 LMsg(0, "Column %d(%d..%d) Line %d(+%d)", cx+1,
741 markdata->left_mar+1, markdata->right_mar+1, W2D(cy)+1, markdata->hist_offset);
742 break;
743 case '\002': /* CTRL-B back one page */
744 if (rep_cnt == 0)
745 rep_cnt = 1;
746 rep_cnt *= fore->w_height;
747 revto(cx, cy - rep_cnt);
748 break;
749 case '\006': /* CTRL-F forward one page */
750 if (rep_cnt == 0)
751 rep_cnt = 1;
752 rep_cnt *= fore->w_height;
753 revto(cx, cy + rep_cnt);
754 break;
755 case '\005': /* CTRL-E scroll up */
756 if (rep_cnt == 0)
757 rep_cnt = 1;
758 rep_cnt = MarkScrollUpDisplay(rep_cnt);
759 if (cy < D2W(0))
760 revto(cx, D2W(0));
761 else
762 LGotoPos(flayer, cx, W2D(cy));
763 break;
764 case '\031': /* CTRL-Y scroll down */
765 if (rep_cnt == 0)
766 rep_cnt = 1;
767 rep_cnt = MarkScrollDownDisplay(rep_cnt);
768 if (cy > D2W(fore->w_height-1))
769 revto(cx, D2W(fore->w_height-1));
770 else
771 LGotoPos(flayer, cx, W2D(cy));
772 break;
773 case '@':
774 /* it may be usefull to have a key that does nothing */
775 break;
776 case '%':
777 rep_cnt--;
778 /* rep_cnt is a percentage for the history buffer */
779 if (rep_cnt < 0)
780 rep_cnt = 0;
781 if (rep_cnt > 100)
782 rep_cnt = 100;
783 revto_line(markdata->left_mar, (rep_cnt * (fore->w_histheight + fore->w_height)) / 100, (fore->w_height - 1) / 2);
784 break;
785 case 0201:
786 case 'g':
787 rep_cnt = 1;
788 /* FALLTHROUGH */
789 case 0205:
790 case 'G':
791 /* rep_cnt is here the WIN line number */
792 if (rep_cnt == 0)
793 rep_cnt = fore->w_histheight + fore->w_height;
794 revto_line(markdata->left_mar, --rep_cnt, (fore->w_height - 1) / 2);
795 break;
796 case 'H':
797 revto(markdata->left_mar, D2W(0));
798 break;
799 case 'M':
800 revto(markdata->left_mar, D2W((fore->w_height - 1) / 2));
801 break;
802 case 'L':
803 revto(markdata->left_mar, D2W(fore->w_height - 1));
804 break;
805 case '|':
806 revto(--rep_cnt, cy);
807 break;
808 case 'w':
809 if (rep_cnt == 0)
810 rep_cnt = 1;
811 nextword(&cx, &cy, NW_MUSTMOVE, rep_cnt);
812 revto(cx, cy);
813 break;
814 case 'e':
815 case 'E':
816 if (rep_cnt == 0)
817 rep_cnt = 1;
818 nextword(&cx, &cy, NW_ENDOFWORD|NW_MUSTMOVE | (od == 'E' ? NW_BIG : 0), rep_cnt);
819 revto(cx, cy);
820 break;
821 case 'b':
822 case 'B':
823 if (rep_cnt == 0)
824 rep_cnt = 1;
825 nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD|NW_MUSTMOVE | (od == 'B' ? NW_BIG : 0), rep_cnt);
826 revto(cx, cy);
827 break;
828 case 'a':
829 markdata->append_mode = 1 - markdata->append_mode;
830 debug1("append mode %d--\n", markdata->append_mode);
831 LMsg(0, (markdata->append_mode) ? ":set append" : ":set noappend");
832 break;
833 case 'v':
834 case 'V':
835 /* this sets start column to column 9 for VI :set nu users */
836 if (markdata->left_mar == 8)
837 rep_cnt = 1;
838 else
839 rep_cnt = 9;
840 /* FALLTHROUGH */
841 case 'c':
842 case 'C':
843 /* set start column (c) and end column (C) */
844 if (markdata->second)
846 rem(markdata->x1, markdata->y1, cx, cy, 1, (char *)0, fore->w_height-1); /* Hack */
847 markdata->second = 1; /* rem turns off second */
849 rep_cnt--;
850 if (rep_cnt < 0)
851 rep_cnt = cx;
852 if (od != 'C')
854 markdata->left_mar = rep_cnt;
855 if (markdata->left_mar > markdata->right_mar)
856 markdata->left_mar = markdata->right_mar;
858 else
860 markdata->right_mar = rep_cnt;
861 if (markdata->left_mar > markdata->right_mar)
862 markdata->right_mar = markdata->left_mar;
864 if (markdata->second)
866 markdata->cx = markdata->x1; markdata->cy = markdata->y1;
867 revto(cx, cy);
869 if (od == 'v' || od == 'V')
870 LMsg(0, (markdata->left_mar != 8) ? ":set nonu" : ":set nu");
871 break;
872 case 'J':
873 /* how do you join lines in VI ? */
874 markdata->nonl = (markdata->nonl + 1) % 4;
875 switch (markdata->nonl)
877 case 0:
878 if (join_with_cr)
879 LMsg(0, "Multiple lines (CR/LF)");
880 else
881 LMsg(0, "Multiple lines (LF)");
882 break;
883 case 1:
884 LMsg(0, "Lines joined");
885 break;
886 case 2:
887 LMsg(0, "Lines joined with blanks");
888 break;
889 case 3:
890 LMsg(0, "Lines joined with comma");
891 break;
893 break;
894 case '/':
895 Search(1);
896 in_mark = 0;
897 break;
898 case '?':
899 Search(-1);
900 in_mark = 0;
901 break;
902 case 'n':
903 Search(0);
904 break;
905 case 'N':
906 markdata->isdir = -markdata->isdir;
907 Search(0);
908 markdata->isdir = -markdata->isdir;
909 break;
910 case 'y':
911 case 'Y':
912 if (markdata->second == 0)
914 revto(linestart(cy), cy);
915 markdata->second++;
916 cx = markdata->x1 = markdata->cx;
917 cy = markdata->y1 = markdata->cy;
919 if (--rep_cnt > 0)
920 revto(cx, cy + rep_cnt);
921 revto(lineend(markdata->cy), markdata->cy);
922 if (od == 'y')
923 break;
924 /* FALLTHROUGH */
925 case 'W':
926 if (od == 'W')
928 if (rep_cnt == 0)
929 rep_cnt = 1;
930 if (!markdata->second)
932 nextword(&cx, &cy, NW_BACK|NW_ENDOFWORD, 1);
933 revto(cx, cy);
934 markdata->second++;
935 cx = markdata->x1 = markdata->cx;
936 cy = markdata->y1 = markdata->cy;
938 nextword(&cx, &cy, NW_ENDOFWORD, rep_cnt);
939 revto(cx, cy);
941 cx = markdata->cx;
942 cy = markdata->cy;
943 /* FALLTHROUGH */
944 case 'A':
945 if (od == 'A')
946 markdata->append_mode = 1;
947 /* FALLTHROUGH */
948 case '>':
949 if (od == '>')
950 markdata->write_buffer = 1;
951 /* FALLTHROUGH */
952 case ' ':
953 case '\r':
954 if (!markdata->second)
956 markdata->second++;
957 markdata->x1 = cx;
958 markdata->y1 = cy;
959 revto(cx, cy);
960 LMsg(0, "First mark set - Column %d Line %d", cx+1, W2D(cy)+1);
961 break;
963 else
965 int append_mode = markdata->append_mode;
966 int write_buffer = markdata->write_buffer;
968 x2 = cx;
969 y2 = cy;
970 newcopylen = rem(markdata->x1, markdata->y1, x2, y2, 2, (char *)0, 0); /* count */
971 if (md_user->u_plop.buf && !append_mode)
972 UserFreeCopyBuffer(md_user);
973 yend = fore->w_height - 1;
974 if (fore->w_histheight - markdata->hist_offset < fore->w_height)
976 markdata->second = 0;
977 yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
979 if (newcopylen > 0)
981 /* the +3 below is for : cr + lf + \0 */
982 if (md_user->u_plop.buf)
983 md_user->u_plop.buf = realloc(md_user->u_plop.buf,
984 (unsigned) (md_user->u_plop.len + newcopylen + 3));
985 else
987 md_user->u_plop.len = 0;
988 md_user->u_plop.buf = malloc((unsigned) (newcopylen + 3));
990 if (!md_user->u_plop.buf)
992 MarkAbort();
993 in_mark = 0;
994 LMsg(0, "Not enough memory... Sorry.");
995 md_user->u_plop.len = 0;
996 md_user->u_plop.buf = 0;
997 break;
999 if (append_mode)
1001 switch (markdata->nonl)
1004 * this code defines, what glues lines together
1006 case 0:
1007 if (join_with_cr)
1009 md_user->u_plop.buf[md_user->u_plop.len] = '\r';
1010 md_user->u_plop.len++;
1012 md_user->u_plop.buf[md_user->u_plop.len] = '\n';
1013 md_user->u_plop.len++;
1014 break;
1015 case 1:
1016 break;
1017 case 2:
1018 md_user->u_plop.buf[md_user->u_plop.len] = ' ';
1019 md_user->u_plop.len++;
1020 break;
1021 case 3:
1022 md_user->u_plop.buf[md_user->u_plop.len] = ',';
1023 md_user->u_plop.len++;
1024 break;
1027 md_user->u_plop.len += rem(markdata->x1, markdata->y1, x2, y2,
1028 markdata->hist_offset == fore->w_histheight,
1029 md_user->u_plop.buf + md_user->u_plop.len, yend);
1030 #ifdef ENCODINGS
1031 md_user->u_plop.enc = fore->w_encoding;
1032 #endif
1034 if (markdata->hist_offset != fore->w_histheight)
1036 LAY_CALL_UP(LRefreshAll(flayer, 0));
1038 ExitOverlayPage();
1039 WindowChanged(fore, 'P');
1040 if (append_mode)
1041 LMsg(0, "Appended %d characters to buffer",
1042 newcopylen);
1043 else
1044 LMsg(0, "Copied %d characters into buffer", md_user->u_plop.len);
1045 if (write_buffer)
1046 WriteFile(md_user, (char *)0, DUMP_EXCHANGE);
1047 in_mark = 0;
1048 break;
1051 case 0222:
1052 if (flayer->l_mouseevent.start)
1054 int button = flayer->l_mouseevent.buffer[0];
1055 if (button == 'a')
1057 /* Scroll down */
1058 od = 'j';
1060 else if (button == '`')
1062 /* Scroll up */
1063 od = 'k';
1065 else if (button == ' ')
1067 /* Left click */
1068 cx = flayer->l_mouseevent.buffer[1];
1069 cy = D2W(flayer->l_mouseevent.buffer[2]);
1070 revto(cx, cy);
1071 od = ' ';
1073 else
1074 od = 0;
1075 LayProcessMouseSwitch(flayer, 0);
1076 if (od)
1077 goto processchar;
1079 else
1080 LayProcessMouseSwitch(flayer, 1);
1081 break;
1083 default:
1084 MarkAbort();
1085 LMsg(0, "Copy mode aborted");
1086 in_mark = 0;
1087 break;
1089 if (in_mark) /* markdata may be freed */
1090 markdata->rep_cnt = 0;
1092 if (in_mark)
1094 flayer->l_x = markdata->cx;
1095 flayer->l_y = W2D(markdata->cy);
1097 *inbufp = pt;
1098 *inlenp = inlen;
1101 void revto(tx, ty)
1102 int tx, ty;
1104 revto_line(tx, ty, -1);
1107 /* tx, ty: WINDOW, line: DISPLAY */
1108 void revto_line(tx, ty, line)
1109 int tx, ty, line;
1111 int fx, fy;
1112 int x, y, t, revst, reven, qq, ff, tt, st, en, ce = 0;
1113 int ystart = 0, yend = fore->w_height-1;
1114 int i, ry;
1115 unsigned char *wi;
1116 struct mline *ml;
1117 struct mchar mc;
1119 if (tx < 0)
1120 tx = 0;
1121 else if (tx > fore->w_width - 1)
1122 tx = fore->w_width -1;
1123 if (ty < 0)
1124 ty = 0;
1125 else if (ty > fore->w_histheight + fore->w_height - 1)
1126 ty = fore->w_histheight + fore->w_height - 1;
1128 fx = markdata->cx; fy = markdata->cy;
1130 #ifdef DW_CHARS
1131 /* don't just move inside of a kanji, the user wants to see something */
1132 ml = WIN(ty);
1133 if (ty == fy && fx + 1 == tx && dw_right(ml, tx, fore->w_encoding) && tx < D_width - 1)
1134 tx++;
1135 if (ty == fy && fx - 1 == tx && dw_right(ml, fx, fore->w_encoding) && tx)
1136 tx--;
1137 #endif
1139 markdata->cx = tx; markdata->cy = ty;
1142 * if we go to a position that is currently offscreen
1143 * then scroll the screen
1145 i = 0;
1146 if (line >= 0 && line < fore->w_height)
1147 i = W2D(ty) - line;
1148 else if (ty < markdata->hist_offset)
1149 i = ty - markdata->hist_offset;
1150 else if (ty > markdata->hist_offset + (fore->w_height - 1))
1151 i = ty - markdata->hist_offset - (fore->w_height - 1);
1152 if (i > 0)
1153 yend -= MarkScrollUpDisplay(i);
1154 else if (i < 0)
1155 ystart += MarkScrollDownDisplay(-i);
1157 if (markdata->second == 0)
1159 flayer->l_x = tx;
1160 flayer->l_y = W2D(ty);
1161 LGotoPos(flayer, tx, W2D(ty));
1162 return;
1165 qq = markdata->x1 + markdata->y1 * fore->w_width;
1166 ff = fx + fy * fore->w_width; /* "from" offset in WIN coords */
1167 tt = tx + ty * fore->w_width; /* "to" offset in WIN coords*/
1169 if (ff > tt)
1171 st = tt; en = ff;
1172 x = tx; y = ty;
1174 else
1176 st = ff; en = tt;
1177 x = fx; y = fy;
1179 if (st > qq)
1181 st++;
1182 x++;
1184 if (en < qq)
1185 en--;
1186 if (tt > qq)
1188 revst = qq; reven = tt;
1190 else
1192 revst = tt; reven = qq;
1194 ry = y - markdata->hist_offset;
1195 if (ry < ystart)
1197 y += (ystart - ry);
1198 x = 0;
1199 st = y * fore->w_width;
1200 ry = ystart;
1202 ml = WIN(y);
1203 for (t = st; t <= en; t++, x++)
1205 if (x >= fore->w_width)
1207 x = 0;
1208 y++, ry++;
1209 ml = WIN(y);
1211 if (ry > yend)
1212 break;
1213 if (t == st || x == 0)
1215 wi = ml->image + fore->w_width;
1216 for (ce = fore->w_width; ce >= 0; ce--, wi--)
1217 if (*wi != ' ')
1218 break;
1220 if (x <= ce && x >= markdata->left_mar && x <= markdata->right_mar)
1222 #ifdef DW_CHARS
1223 if (dw_right(ml, x, fore->w_encoding))
1225 if (t == revst)
1226 revst--;
1227 t--;
1228 x--;
1230 #endif
1231 if (t >= revst && t <= reven)
1233 mc = mchar_so;
1234 #ifdef FONT
1235 if (pastefont)
1236 mc.font = ml->font[x];
1237 #endif
1238 mc.image = ml->image[x];
1240 else
1241 copy_mline2mchar(&mc, ml, x);
1242 #ifdef DW_CHARS
1243 if (dw_left(ml, x, fore->w_encoding))
1245 mc.mbcs = ml->image[x + 1];
1246 LPutChar(flayer, &mc, x, W2D(y));
1247 t++;
1249 #endif
1250 LPutChar(flayer, &mc, x, W2D(y));
1251 #ifdef DW_CHARS
1252 if (dw_left(ml, x, fore->w_encoding))
1253 x++;
1254 #endif
1257 flayer->l_x = tx;
1258 flayer->l_y = W2D(ty);
1259 LGotoPos(flayer, tx, W2D(ty));
1262 static void
1263 MarkAbort()
1265 int yend, redisp;
1267 debug("MarkAbort\n");
1268 markdata = (struct markdata *)flayer->l_data;
1269 fore = markdata->md_window;
1270 yend = fore->w_height - 1;
1271 redisp = markdata->second;
1272 if (fore->w_histheight - markdata->hist_offset < fore->w_height)
1274 markdata->second = 0;
1275 yend -= MarkScrollUpDisplay(fore->w_histheight - markdata->hist_offset);
1277 if (markdata->hist_offset != fore->w_histheight)
1279 LAY_CALL_UP(LRefreshAll(flayer, 0));
1281 else
1283 rem(markdata->x1, markdata->y1, markdata->cx, markdata->cy, redisp, (char *)0, yend);
1285 ExitOverlayPage();
1286 WindowChanged(fore, 'P');
1290 static void
1291 MarkRedisplayLine(y, xs, xe, isblank)
1292 int y; /* NOTE: y is in DISPLAY coords system! */
1293 int xs, xe;
1294 int isblank;
1296 int wy, x, i, rm;
1297 int sta, sto, cp; /* NOTE: these 3 are in WINDOW coords system */
1298 unsigned char *wi;
1299 struct mline *ml;
1300 struct mchar mchar_marked;
1302 if (y < 0) /* No special full page handling */
1303 return;
1305 markdata = (struct markdata *)flayer->l_data;
1306 fore = markdata->md_window;
1308 mchar_marked = mchar_so;
1310 wy = D2W(y);
1311 ml = WIN(wy);
1313 if (markdata->second == 0)
1315 if (dw_right(ml, xs, fore->w_encoding) && xs > 0)
1316 xs--;
1317 if (dw_left(ml, xe, fore->w_encoding) && xe < fore->w_width - 1)
1318 xe++;
1319 if (xs == 0 && y > 0 && wy > 0 && WIN(wy - 1)->image[flayer->l_width] == 0)
1320 LCDisplayLineWrap(flayer, ml, y, xs, xe, isblank);
1321 else
1322 LCDisplayLine(flayer, ml, y, xs, xe, isblank);
1323 return;
1326 sta = markdata->y1 * fore->w_width + markdata->x1;
1327 sto = markdata->cy * fore->w_width + markdata->cx;
1328 if (sta > sto)
1330 i=sta; sta=sto; sto=i;
1332 cp = wy * fore->w_width + xs;
1334 rm = markdata->right_mar;
1335 for (x = fore->w_width, wi = ml->image + fore->w_width; x >= 0; x--, wi--)
1336 if (*wi != ' ')
1337 break;
1338 if (x < rm)
1339 rm = x;
1341 for (x = xs; x <= xe; x++, cp++)
1342 if (cp >= sta && x >= markdata->left_mar)
1343 break;
1344 #ifdef DW_CHARS
1345 if (dw_right(ml, x, fore->w_encoding))
1346 x--;
1347 #endif
1348 if (x > xs)
1349 LCDisplayLine(flayer, ml, y, xs, x - 1, isblank);
1350 for (; x <= xe; x++, cp++)
1352 if (cp > sto || x > rm)
1353 break;
1354 #ifdef FONT
1355 if (pastefont)
1356 mchar_marked.font = ml->font[x];
1357 #endif
1358 mchar_marked.image = ml->image[x];
1359 #ifdef DW_CHARS
1360 mchar_marked.mbcs = 0;
1361 if (dw_left(ml, x, fore->w_encoding))
1363 mchar_marked.mbcs = ml->image[x + 1];
1364 cp++;
1366 #endif
1367 LPutChar(flayer, &mchar_marked, x, y);
1368 #ifdef DW_CHARS
1369 if (dw_left(ml, x, fore->w_encoding))
1370 x++;
1371 #endif
1373 if (x <= xe)
1374 LCDisplayLine(flayer, ml, y, x, xe, isblank);
1379 * This ugly routine is to speed up GotoPos()
1381 static int
1382 MarkRewrite(ry, xs, xe, rend, doit)
1383 int ry, xs, xe, doit;
1384 struct mchar *rend;
1386 int dx, x, y, st, en, t, rm;
1387 unsigned char *i;
1388 struct mline *ml;
1389 struct mchar mchar_marked;
1391 mchar_marked = mchar_so;
1393 debug3("MarkRewrite %d, %d-%d\n", ry, xs, xe);
1394 markdata = (struct markdata *)flayer->l_data;
1395 fore = markdata->md_window;
1396 y = D2W(ry);
1397 ml = WIN(y);
1398 #ifdef UTF8
1399 if (fore->w_encoding && fore->w_encoding != UTF8 && D_encoding == UTF8 && ContainsSpecialDeffont(ml, xs, xe, fore->w_encoding))
1400 return EXPENSIVE;
1401 #endif
1402 dx = xe - xs + 1;
1403 if (doit)
1405 i = ml->image + xs;
1406 while (dx--)
1407 PUTCHAR(*i++);
1408 return 0;
1411 if (markdata->second == 0)
1412 st = en = -1;
1413 else
1415 st = markdata->y1 * fore->w_width + markdata->x1;
1416 en = markdata->cy * fore->w_width + markdata->cx;
1417 if (st > en)
1419 t = st; st = en; en = t;
1422 t = y * fore->w_width + xs;
1423 for (rm = fore->w_width, i = ml->image + fore->w_width; rm >= 0; rm--)
1424 if (*i-- != ' ')
1425 break;
1426 if (rm > markdata->right_mar)
1427 rm = markdata->right_mar;
1428 x = xs;
1429 while (dx--)
1431 if (t >= st && t <= en && x >= markdata->left_mar && x <= rm)
1433 #ifdef FONT
1434 if (pastefont)
1435 mchar_marked.font = ml->font[x];
1436 #endif
1437 rend->image = mchar_marked.image;
1438 if (!cmp_mchar(rend, &mchar_marked))
1439 return EXPENSIVE;
1441 else
1443 rend->image = ml->image[x];
1444 if (!cmp_mchar_mline(rend, ml, x))
1445 return EXPENSIVE;
1447 x++;
1449 return xe - xs + 1;
1454 * scroll the screen contents up/down.
1456 static int MarkScrollUpDisplay(n)
1457 int n;
1459 int i;
1461 debug1("MarkScrollUpDisplay(%d)\n", n);
1462 if (n <= 0)
1463 return 0;
1464 if (n > fore->w_histheight - markdata->hist_offset)
1465 n = fore->w_histheight - markdata->hist_offset;
1466 markdata->hist_offset += n;
1467 i = (n < flayer->l_height) ? n : (flayer->l_height);
1468 LScrollV(flayer, i, 0, flayer->l_height - 1, 0);
1469 while (i-- > 0)
1470 MarkRedisplayLine(flayer->l_height - i - 1, 0, flayer->l_width - 1, 1);
1471 return n;
1474 static int
1475 MarkScrollDownDisplay(n)
1476 int n;
1478 int i;
1480 debug1("MarkScrollDownDisplay(%d)\n", n);
1481 if (n <= 0)
1482 return 0;
1483 if (n > markdata->hist_offset)
1484 n = markdata->hist_offset;
1485 markdata->hist_offset -= n;
1486 i = (n < flayer->l_height) ? n : (flayer->l_height);
1487 LScrollV(flayer, -i, 0, fore->w_height - 1, 0);
1488 while (i-- > 0)
1489 MarkRedisplayLine(i, 0, flayer->l_width - 1, 1);
1490 return n;
1493 void
1494 MakePaster(pa, buf, len, bufiscopy)
1495 struct paster *pa;
1496 char *buf;
1497 int len;
1498 int bufiscopy;
1500 FreePaster(pa);
1501 pa->pa_pasteptr = buf;
1502 pa->pa_pastelen = len;
1503 if (bufiscopy)
1504 pa->pa_pastebuf = buf;
1505 pa->pa_pastelayer = flayer;
1506 DoProcess(Layer2Window(flayer), &pa->pa_pasteptr, &pa->pa_pastelen, pa);
1509 void
1510 FreePaster(pa)
1511 struct paster *pa;
1513 if (pa->pa_pastebuf)
1514 free(pa->pa_pastebuf);
1515 pa->pa_pastebuf = 0;
1516 pa->pa_pasteptr = 0;
1517 pa->pa_pastelen = 0;
1518 pa->pa_pastelayer = 0;
1519 evdeq(&pa->pa_slowev);
1522 #endif /* COPY_PASTE */