1 /*
2  *  fbcmdmove.cc
3  *
4  *  Copyright (C) 1998  Jiann-Ching Liu
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "qe_config.h"
11 #include "colors.h"
12 #include "keymap.h"
13 #include "filebuffer.h"
14 #include <ctype.h>
15 
16 /***************************************************************************/
17 // check character is word smymbol
18 //
19 
isword(int ch)20 int filebuffer::isword(int ch) {
21 
22     return(isalpha(ch) || isdigit(ch) || ch=='_');
23 }
24 
cmd_beginline(void)25 int filebuffer::cmd_beginline(void) {
26     if (mode == FB_DATAAREA_MODE) {
27         cursor_x = buffer_x = workbufidx = 0;
28         if (left_col_no != 0) {
29             left_col_no = 0;
30             refresh_clientarea(1);
31         }
32     } else {
33         if (cmdline_idx < screen_x -1) {
34             cmdline_idx = 0;
35         } else {
36             cmdline_idx = 0;
37             refresh_cmdarea();
38         }
39     }
40     return 0;
41 }
42 
43 
44 
cmd_endline(void)45 int filebuffer::cmd_endline(void) {
46     if (mode == FB_DATAAREA_MODE) {
47         buffer_x = workbuflen;
48         workbufidx = workbuflen;
49 
50         if (workbuflen < screen_x) {
51             cursor_x = workbuflen;
52             if (left_col_no != 0) {
53                 left_col_no = 0;
54                 refresh_clientarea(1);
55             }
56         } else {
57             unsigned int   tmpval = left_col_no;
58             cursor_x = screen_x - 1;
59             left_col_no = workbuflen - screen_x + 1;
60             if (left_col_no != tmpval) {
61                 refresh_clientarea(1);
62             }
63         }
64     } else {
65         int  oldval = cmdline_idx;
66 
67         if ((cmdline_idx = strlen(cmdline)) != oldval) {
68             refresh_cmdarea();
69         }
70     }
71     return 0;
72 }
73 
cmd_left(void)74 int filebuffer::cmd_left(void) {
75     if (mode == FB_DATAAREA_MODE) {
76         workbufidx = workbufidx > 0 ? workbufidx - 1 : 0;
77         buffer_x   = workbufidx;
78 
79         if (cursor_x > 0) {
80             cursor_x--;
81         } else {
82             if (left_col_no != 0) {
83                 left_col_no--;
84                 refresh_clientarea(1);
85             }
86         }
87     } else {
88         int oldval = cmdline_idx;
89 
90         cmdline_idx = cmdline_idx > 0 ? cmdline_idx - 1 : 0;
91 
92         if (oldval > screen_x + 1)
93             refresh_cmdarea();
94     }
95     return 0;
96 }
97 
cmd_right(void)98 int filebuffer::cmd_right(void) {
99     if (mode == FB_DATAAREA_MODE) {
100         if (workbufidx < MAX_BUFFER_LEN-2) {
101             workbufidx = workbufidx + 1;
102             buffer_x   = workbufidx;
103             if (cursor_x < screen_x - 1) {
104                 cursor_x++;
105             } else {
106                 left_col_no++;
107                 refresh_clientarea(1);
108             }
109         }
110     } else {
111         int  len = strlen(cmdline);
112         cmdline_idx = cmdline_idx < len ? cmdline_idx + 1 : len;
113 
114         if (cmdline_idx >= screen_x + 1)
115             refresh_cmdarea();
116     }
117     return 0;
118 }
119 
cmd_tab(void)120 int filebuffer::cmd_tab(void) {
121     for (int i = buffer_x % TAB_SPACE; i < TAB_SPACE; i++)
122         cmd_right();
123     return 0;
124 }
125 
126 
127 ////////////////////////////////////////////////////////////////////////
128 
129 
cmd_up(void)130 int filebuffer::cmd_up(void) {
131     cmd_cursor_data();
132 
133     if (buffer_y > 0) {
134         write_workbuffer(QE_IF_NECESSARY);
135         buffer_y--;
136         current = current->previous;
137         if (cursor_y == 0) {
138             top_line_no--;
139             topline = topline->previous;
140             refresh_clientarea(0);
141         } else {
142             cursor_y--;
143         }
144         load_workbuffer();
145     } else {
146         if (top_line_no != -1) {
147             top_line_no = -1;
148             topline = head;
149             cursor_y++;
150             refresh_clientarea(1);
151         }
152     }
153     return 0;
154 }
155 
cmd_down(void)156 int filebuffer::cmd_down(void) {
157     cmd_cursor_data();
158 
159     if (buffer_y < total_line - 1) {
160         write_workbuffer(QE_IF_NECESSARY);
161         buffer_y++;
162         current = current->next;
163         if (cursor_y == screen_y-4) {
164             top_line_no++;
165             topline = topline->next;
166             refresh_clientarea(0);
167         } else {
168             cursor_y++;
169         }
170         load_workbuffer();
171     } else {
172         if (cursor_y == screen_y-4) {
173             top_line_no++;
174             topline = topline->next;
175             cursor_y--;
176             refresh_clientarea(1);
177         }
178     }
179     return 0;
180 }
181 
cmd_pgup(void)182 int filebuffer::cmd_pgup(void) {
183     if (top_line_no != -1) {
184         write_workbuffer(QE_IF_NECESSARY);
185         for (int i = 1; top_line_no >= 0 && i < screen_y-3; i++) {
186             topline = topline->previous;
187             top_line_no--;
188 
189             if (buffer_y > 0) {
190                 current = current->previous;
191                 buffer_y--;
192             } else {
193                 cursor_y++;
194             }
195       }
196       refresh_clientarea(0);
197       load_workbuffer();
198     }
199     return 0;
200 }
201 
cmd_pgdn(void)202 int filebuffer::cmd_pgdn(void) {
203     if (top_line_no + screen_y - 4 < total_line) {
204         write_workbuffer(QE_IF_NECESSARY);
205         for (int i = 1; top_line_no + screen_y - 4 < total_line &&
206                                       i <  screen_y-3; i++, top_line_no++) {
207             topline = topline->next;
208             if (buffer_y < total_line - 1) {
209                 current = current->next;
210                 buffer_y++;
211             } else {
212                 cursor_y--;
213             }
214         }
215         refresh_clientarea(0);
216         load_workbuffer();
217     }
218     return 0;
219 }
220 
cmd_top(void)221 int filebuffer::cmd_top(void) {
222     cmd_cursor_data();
223     if (buffer_y != 0) {
224         write_workbuffer(QE_IF_NECESSARY);
225         buffer_y    = 0;
226         cursor_y    = 1;
227         top_line_no = -1;
228         topline     = head;
229         current     = head->next;
230         refresh_clientarea(0);
231         load_workbuffer();
232     }
233 
234     return 0;
235 }
236 
cmd_bottom(void)237 int filebuffer::cmd_bottom(void) {
238     int    i;
239 
240     cmd_cursor_data();
241 
242     if (buffer_y != total_line - 1) {
243         write_workbuffer(QE_IF_NECESSARY);
244 
245         buffer_y = total_line - 1;
246         current  = tail->previous;
247 
248         topline     = current;
249         top_line_no = buffer_y;
250 
251         for (i = 0; i < screen_y-5 && top_line_no >= 0 ; i++) {
252             topline = topline->previous;
253             top_line_no--;
254         }
255         cursor_y = i;
256         refresh_clientarea(0);
257         load_workbuffer();
258     }
259     return 0;
260 }
261 
cmd_top_edge(void)262 int filebuffer::cmd_top_edge(void) {
263     int   updateflag = 0;
264 
265     cmd_cursor_data();
266 
267     while ((buffer_y > top_line_no) && (buffer_y > 0)) {
268         if (! updateflag) write_workbuffer(QE_IF_NECESSARY);
269         updateflag = 1;
270         buffer_y--;
271         cursor_y--;
272         current = current->previous;
273     }
274 
275     if (updateflag) load_workbuffer();
276 
277     return 0;
278 }
279 
cmd_bottom_edge(void)280 int filebuffer::cmd_bottom_edge(void) {
281     int   updateflag = 0;
282 
283     cmd_cursor_data();
284 
285     while ((buffer_y < top_line_no + screen_y -4)&&(buffer_y < total_line-1)) {
286         if (! updateflag) write_workbuffer(QE_IF_NECESSARY);
287         updateflag = 1;
288         buffer_y++;
289         cursor_y++;
290         current = current->next;
291     }
292 
293     if (updateflag) load_workbuffer();
294 
295     return 0;
296 }
297 
cmd_scrollup(void)298 int filebuffer::cmd_scrollup(void) {
299     cmd_cursor_data();
300 
301     if (top_line_no + screen_y - 4 < total_line) {
302         write_workbuffer(QE_IF_NECESSARY);
303         top_line_no++;
304         topline = topline->next;
305         if (buffer_y == total_line-1) {
306             cursor_y--;
307         } else {
308             current = current->next;
309             buffer_y++;
310         }
311         load_workbuffer();
312         refresh_clientarea(0);
313     } else {
314         return cmd_down();
315     }
316     // wprintw(win, "[scrollup]");
317     return 0;
318 }
319 
cmd_scrolldown(void)320 int filebuffer::cmd_scrolldown(void) {
321     cmd_cursor_data();
322 
323     if (top_line_no > -1 && buffer_y > 0) {
324         write_workbuffer(QE_IF_NECESSARY);
325         top_line_no--;
326         topline = topline->previous;
327         current = current->previous;
328         buffer_y--;
329         load_workbuffer();
330         refresh_clientarea(0);
331     } else {
332         return cmd_up();
333     }
334     return 0;
335 }
336 
cmd_scrollleft(void)337 int filebuffer::cmd_scrollleft(void) {
338     cmd_cursor_data();
339 
340     if (left_col_no + screen_x < MAX_BUFFER_LEN-1) {
341         unsigned int  org = left_col_no;
342 
343         cmd_right();
344 
345         if (org == left_col_no) {
346             left_col_no++;
347             cursor_x--;
348             refresh_clientarea(1);
349         }
350     } else {
351         cmd_right();
352     }
353     return 0;
354 }
355 
cmd_scrollright(void)356 int filebuffer::cmd_scrollright(void) {
357     cmd_cursor_data();
358     if (left_col_no > 0) {
359         unsigned int  org = left_col_no;
360 
361         cmd_left();
362 
363         if (org == left_col_no) {
364             left_col_no--;
365             cursor_x++;
366             refresh_clientarea(1);
367         }
368     } else {
369         cmd_left();
370     }
371     return 0;
372 }
373 
374 /***************************************************************************/
375 // Move cursor end of word
376 // Macro  : [end word] [we]
377 // Status : OK
378 //
379 
cmd_wordend(void)380 int filebuffer::cmd_wordend(void) {
381     cmd_cursor_data();
382 
383 
384     while (isword(workbuffer[workbufidx]) && workbufidx< workbuflen)
385     {
386         moveto(buffer_y, workbufidx);
387         workbufidx++;
388     }
389 
390     return 0;
391 }
392 
393 /***************************************************************************/
394 // Move cursor begin of word
395 // Macro  : [begin word] [wb]
396 // Status : OK
397 //
398 
cmd_wordbegin(void)399 int filebuffer::cmd_wordbegin(void) {
400     cmd_cursor_data();
401 
402     while (isword(workbuffer[workbufidx]) && workbufidx>0)
403     {
404         moveto(buffer_y, workbufidx);
405         workbufidx--;
406     }
407 
408     return 0;
409 }
410 
411 /***************************************************************************/
412 // Move cursor to next word
413 // Macro  : [next word] [nw]
414 // Status : OK
415 //
416 
cmd_wordnext(void)417 int filebuffer::cmd_wordnext(void) {
418     cmd_cursor_data();
419 
420     while (isword(workbuffer[workbufidx]) && workbufidx< workbuflen)
421     {
422         moveto(buffer_y, workbufidx);
423         workbufidx++;
424     }
425 
426     while (!isword(workbuffer[workbufidx]) && workbufidx< workbuflen)
427     {
428         moveto(buffer_y, workbufidx);
429         workbufidx++;
430     }
431     return 0;
432 }
433 
434 /***************************************************************************/
435 // Drop Anchor bookmark0
436 // Macro  : [set0]
437 // Status : OK
438 // Remark : Better use for system internal use
439 
cmd_setbook0(void)440 int filebuffer::cmd_setbook0(void) {
441 
442     setbook0x = workbufidx;
443     setbook0y = buffer_y;
444     return 0;
445 }
446 
447 /***************************************************************************/
448 // Drop Anchor bookmark1
449 // Macro  : [set1]
450 // Status : OK
451 
cmd_setbook1(void)452 int filebuffer::cmd_setbook1(void) {
453 
454     setbook1x = workbufidx;
455     setbook1y = buffer_y;
456     return 0;
457 }
458 
459 /***************************************************************************/
460 // Drop Anchor bookmark2
461 // Macro  : [set2]
462 // Status : OK
463 
cmd_setbook2(void)464 int filebuffer::cmd_setbook2(void) {
465 
466     setbook2x = workbufidx;
467     setbook2y = buffer_y;
468     return 0;
469 }
470 
471 /***************************************************************************/
472 // go Anchor bookmark0
473 // Macro  : [go0]
474 // Status : OK
475 // Remark : Better use for system internal use
476 
cmd_gobook0(void)477 int filebuffer::cmd_gobook0(void) {
478     cmd_cursor_data();
479     moveto(setbook0y, setbook0x);
480     workbufidx = setbook0x;
481     buffer_y = setbook0y;
482     return 0;
483 }
484 
485 /***************************************************************************/
486 // go Anchor bookmark1
487 // Macro  : [go1]
488 // Status : OK
489 //
490 
cmd_gobook1(void)491 int filebuffer::cmd_gobook1(void) {
492     cmd_cursor_data();
493     moveto(setbook1y, setbook1x);
494     workbufidx = setbook1x;
495     buffer_y = setbook1y;
496     return 0;
497 }
498 
499 /***************************************************************************/
500 // go Anchor bookmark2
501 // Macro  : [go2]
502 // Status : OK
503 //
504 //
505 
cmd_gobook2(void)506 int filebuffer::cmd_gobook2(void) {
507     cmd_cursor_data();
508     moveto(setbook2y, setbook2x);
509     workbufidx = setbook2x;
510     buffer_y = setbook2y;
511     return 0;
512 }
513 
514 /***************************************************************************/
515 // duplicate upper line char
516 // status : not finish
517 // I don't know how to place chatactor to current buffer
518 // but it's easy to replace by macro
519 // [up][mb][down][cm][unmark][right]
520 
cmd_dupchar(void)521 int filebuffer::cmd_dupchar(void) {
522     char ch;
523 
524     cmd_cursor_data();
525 
526     write_workbuffer(QE_IF_NECESSARY);
527 
528     if (buffer_y>1) {
529        buffer_y--;
530        current = current->previous;
531        load_workbuffer();
532        ch = workbuffer[workbufidx];
533        printf("%d",ch);
534        buffer_y++;
535        current = current->next;
536        workbuffer[workbufidx++]=ch;
537        mvwinsch(win,buffer_y,workbufidx,ch);
538        moveto(buffer_y,workbufidx);
539        refresh_clientarea(0);
540     }
541     return 0;
542 }
543 
544 
545 
cmd_centerline(void)546 int filebuffer::cmd_centerline(void) {
547     int    cl = (screen_y - 3) / 2;
548     int    oldy = cursor_y;
549 
550     cmd_cursor_data();
551 
552     while (topline != head && cursor_y < cl) {
553         topline = topline->previous;
554         top_line_no--;
555         cursor_y++;
556     }
557 
558     while (cursor_y > cl) {
559         topline = topline->next;
560         top_line_no++;
561         cursor_y--;
562     }
563     if (oldy != cursor_y) refresh_clientarea(1);
564     return 0;
565 }
566 
cmd_backword(void)567 int filebuffer::cmd_backword(void) {
568     int  i, found;
569 
570     for (i = buffer_x; i >= 0; i--)
571         if (workbuffer[i] == ' ') break;
572 
573     for (found = 0; i >= 0; i--) {
574         if (workbuffer[i] != ' ') {
575             found = 1;
576             break;
577         }
578     }
579 
580     if (found) {
581         int need_refresh;
582 
583         for (; i > 0; i--)
584             if (workbuffer[i-1] == ' ') break;
585 
586         for (need_refresh = 0; workbufidx > i; workbufidx--, buffer_x--) {
587             if (cursor_x > 0) {
588                 cursor_x--;
589             } else {
590                 left_col_no--;
591                 need_refresh = 1;
592             }
593         }
594         if (need_refresh) refresh_clientarea(1);
595     } else if (current->previous != head) {
596         cmd_up();
597         cmd_endline();
598         return cmd_backword();
599     }
600 
601     return 0;
602 }
603 
cmd_tabword(void)604 int filebuffer::cmd_tabword(void) {
605     static  int   level = 0;
606     int           i, found;
607 
608     i = buffer_x;
609 
610     if (level++ == 0)
611         for (; i < workbuflen; i++)
612             if (workbuffer[i] == ' ')
613                 break;
614 
615     for (found = 0; i < workbuflen; i++) {
616         if (workbuffer[i] != ' ') {
617             found = 1;
618             break;
619         }
620     }
621 
622     if (found) {
623         int need_refresh;
624 
625         for (need_refresh = 0; workbufidx < i; workbufidx++, buffer_x++) {
626             if (cursor_x < screen_x - 1) {
627                 cursor_x++;
628             } else {
629                 left_col_no++;
630                 need_refresh = 1;
631             }
632         }
633         if (need_refresh) refresh_clientarea(1);
634     } else if (current->next != tail) {
635         cmd_down();
636         cmd_beginline();
637         cmd_tabword();
638     }
639     level--;
640     return 0;
641 }
642 
moveto(const int y,const int x)643 void filebuffer::moveto(const int y, const int x) {
644     int  need_refresh = 0;
645 
646     write_workbuffer(QE_IF_NECESSARY);
647 
648     if (y < top_line_no) {
649         int yy = maximum(y, 0);
650 
651         for (; top_line_no > -1 && buffer_y > yy; buffer_y--) {
652             topline = topline->previous;
653             current = current->previous;
654             top_line_no--;
655         }
656 
657         for (; buffer_y > yy; buffer_y--) {
658             current = current->previous;
659             cursor_y--;
660         }
661 
662         need_refresh = 1;
663     } else if (y > top_line_no + screen_y - 4) {
664         int  yy = minimum(y, total_line-1);
665 
666         for (; buffer_y < yy; buffer_y++) {
667             topline = topline->next;
668             current  = current->next;
669             top_line_no++;
670         }
671         need_refresh = 1;
672     } else {
673         for (; buffer_y > y; buffer_y--) {
674             current = current->previous;
675             cursor_y--;
676         }
677         for (; buffer_y < y; buffer_y++) {
678             current = current->next;
679             cursor_y++;
680         }
681     }
682 
683     unsigned int xx = minimum(maximum(x, 0), MAX_BUFFER_LEN-1);
684 
685     if (xx < left_col_no || xx > left_col_no + screen_x - 1) {
686         left_col_no = 0;
687 
688         for (left_col_no = 0; xx > left_col_no + screen_x - 1; left_col_no++)
689             ;
690         need_refresh = 1;
691     }
692 
693     buffer_x = xx;
694     cursor_x = buffer_x - left_col_no;
695 
696     load_workbuffer();
697 
698     if (need_refresh) refresh_clientarea(0);
699 }
700 
701 
cmd_gotoline(void)702 int filebuffer::cmd_gotoline(void) {
703     WINDOW     *mw;
704     char       buffer[MAX_BUFFER_LEN+1];
705     int        key, idx = 0, len = 0;
706     int        finish = 0;
707     const char linenumstr[] = "Line Number: ";
708     char       fmt[10];
709     int        startpos = strlen(linenumstr) + 2;
710     const int  numlen = 12;
711 
712 
713     int width = startpos + numlen + 2;
714 
715     mw = newwin(3, width, screen_y / 2 - 2, (screen_x - width)/ 2 );
716 
717     setattr(mw, ATTRIBUTE_goto_text);
718 
719     sprintf(fmt, " %%-%ds", width-3);
720 
721     box(mw, 0, 0);
722     mvwprintw(mw, 1, 1, fmt, linenumstr);
723     keypad(mw, TRUE);
724     nodelay(mw, FALSE);
725 
726     sprintf(fmt, "%%-%ds", numlen);
727 
728     wmove(mw, 1, startpos);
729 
730     while (! finish) {
731         switch(key = wgetch(mw)) {
732         case KEY_LEFT:
733             if (idx > 0) {
734                 idx--;
735                 wmove(mw, 1, startpos + idx);
736             }
737             break;
738         case KEY_RIGHT:
739             if (idx < len) {
740                 idx++;
741                 wmove(mw, 1, startpos + idx);
742             }
743             break;
744         case KEY_BACKSPACE:
745         case KEY_DC:
746             if (idx < len) {
747                 for (int i = idx; i < len; i++)
748                     buffer[i] = buffer[i+1];
749                 buffer[--len] = '\0';
750                 mvwprintw(mw, 1, startpos, fmt, buffer);
751                 wmove(mw, 1, startpos + idx);
752             }
753             break;
754         case ' ':
755             finish = 1;
756             break;
757         case KEY_ENTER:
758         case KEY_RETURN:
759         case KEY_LINEFEED:
760             finish = 2;
761             break;
762         default:
763             if (key >= '0' && key <= '9') {
764                 if (idx < numlen) {
765                     buffer[idx] = key;
766                     mvwaddch(mw, 1, startpos + idx, key);
767                     idx++;
768                     len = maximum(len, idx);
769                 } else {
770                     beep();
771                 }
772             }
773             break;
774         }
775     }
776 
777     delwin(mw);
778     touchwin(win);
779     wrefresh(win);
780 
781     if (finish == 2 && len > 0) {
782         buffer[len] = '\0';
783         moveto(atoi(buffer)-1, buffer_x);
784     }
785 
786     return 0;
787 }
788 
cmd_goto_currline(int cy,int cx)789 int filebuffer::cmd_goto_currline(int cy, int cx) {
790       cmd_cursor_data();
791       moveto(cy, cx);
792       buffer_y = cy;
793       workbufidx = cx;
794       return 0;
795 
796 }
797 
798 /***************************************************************************/
799 // move cursor to line number
800 // macro  : [goto line]
801 // status : OK
802 
803 
cmd_goto_line(void)804 int filebuffer::cmd_goto_line(void) {
805     static char str[7];
806     static char idx = 0;
807     int         key = 0;
808     int   curr_line = 0;
809     const char  *fmtstr = "Ctrl-G: stop. Goto Line: %s";
810     str[idx] = '\0';
811     display_messages(fmtstr, str);
812 
813     write_workbuffer(QE_IF_NECESSARY);
814 
815     while (1) {
816        for (int finish = 0; ! finish;) {
817        if (isdigit(key = wgetch(win))) {
818         str[idx] = key;
819         idx = (idx < 5) ? idx+1 : idx;
820         } else {
821           switch (key) {
822            case KEY_ENTER:
823            case KEY_RETURN:
824            case KEY_LINEFEED:
825                 curr_line = atoi(str)-1;         // get input line number
826                 cmd_goto_currline(curr_line, workbufidx);
827                 finish = 1;
828                 return 0;
829            case KEY_BACKSPACE:
830                 idx = (idx > 0) ? idx-1 : idx;
831                 str[idx] = '\0';                 // end of string
832                 display_messages(fmtstr, str);   // update string
833                 break;
834            case KEY_CTRL('g'):
835                 cmd_cursor_data();
836                 display_messages();
837                 return 0;
838            default:
839                 break;
840 
841 
842          } // end of switch
843         }
844         str[idx] = '\0';
845         display_messages(fmtstr, str);
846 
847 
848        }  // end of isdigit
849      }
850      return 0;
851 }
852 
853 /***************************************************************************/
854 // mark work under cursor
855 // macro  : [mark word]
856 // status : OK
857 
cmd_markword(void)858 int filebuffer::cmd_markword(void) {
859     int  idx=0;
860 
861     cmd_cursor_data();
862     cmd_unmark();
863     cmd_setbook0();         // save current position in templete book
864     cmd_wordbegin();        // begin of word
865     cmd_right();
866     cmd_markblock();
867     write_workbuffer(QE_IF_NECESSARY);
868     while (isword(workbuffer[workbufidx]) && workbufidx< workbuflen)
869     {
870         if (idx>21) break;
871         patstr[idx++]=workbuffer[workbufidx];
872         moveto(buffer_y, workbufidx);
873         workbufidx++;
874     }
875     patstr[idx]='\0';
876     cmd_markblock();
877     cmd_gobook0();
878 //    printf("%s",patstr);
879     return 0;
880 }
881 
882 
883