1 /******************************************************************************
2 * This file is part of TinTin++ *
3 * *
4 * Copyright 2004-2020 Igor van den Hoven *
5 * *
6 * TinTin++ is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with TinTin++. If not, see https://www.gnu.org/licenses. *
18 ******************************************************************************/
19
20 /******************************************************************************
21 * T I N T I N + + *
22 * *
23 * coded by Igor van den Hoven 2006 *
24 ******************************************************************************/
25
26 #include "tintin.h"
27
DO_COMMAND(do_cursor)28 DO_COMMAND(do_cursor)
29 {
30 int cnt;
31
32 arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
33
34 if (*arg1 == 0)
35 {
36 tintin_header(ses, 80, " CURSOR OPTIONS ");
37
38 for (cnt = 0 ; cursor_table[cnt].fun ; cnt++)
39 {
40 if (*cursor_table[cnt].desc)
41 {
42 convert_meta(cursor_table[cnt].code, arg2, FALSE);
43
44 tintin_printf2(ses, " [%-18s] [%-8s] %s", cursor_table[cnt].name, arg2, cursor_table[cnt].desc);
45 }
46 }
47 tintin_header(ses, 80, "");
48 }
49 else
50 {
51 for (cnt = 0 ; *cursor_table[cnt].name ; cnt++)
52 {
53 if (is_abbrev(arg1, cursor_table[cnt].name))
54 {
55 cursor_table[cnt].fun(ses, arg);
56
57 return ses;
58 }
59 }
60 show_error(ses, LIST_COMMAND, "#ERROR: #CURSOR {%s} IS NOT A VALID OPTION.", arg1);
61 }
62 return ses;
63 }
64
65 // strlen with offset.
66
inputline_str_str_len(int start,int end)67 int inputline_str_str_len(int start, int end)
68 {
69 int raw_cnt, str_cnt, ret_cnt, width;
70
71 raw_cnt = str_cnt = ret_cnt = 0;
72
73 while (raw_cnt < gtd->ses->input->raw_len)
74 {
75 if (str_cnt >= end)
76 {
77 break;
78 }
79
80 raw_cnt += get_vt102_width(gtd->ses, >d->ses->input->buf[raw_cnt], &width);
81
82 if (str_cnt >= start)
83 {
84 ret_cnt += width;
85 }
86 str_cnt += width;
87 }
88 return ret_cnt;
89 }
90
91 // raw range
92
inputline_raw_str_len(int raw_start,int raw_end)93 int inputline_raw_str_len(int raw_start, int raw_end)
94 {
95 int raw_cnt, str_len, size, width;
96
97 raw_cnt = raw_start;
98 str_len = 0;
99
100 while (raw_cnt < gtd->ses->input->raw_len)
101 {
102 if (raw_end >= 0 && raw_cnt >= raw_end)
103 {
104 break;
105 }
106
107 size = get_vt102_width(gtd->ses, >d->ses->input->buf[raw_cnt], &width);
108
109 raw_cnt += size;
110 str_len += width;
111 }
112 return str_len;
113 }
114
115 // display range
116
inputline_str_raw_len(int str_start,int str_end)117 int inputline_str_raw_len(int str_start, int str_end)
118 {
119 int raw_cnt, str_cnt, ret_cnt, size, width;
120
121 raw_cnt = str_cnt = ret_cnt = 0;
122
123 while (raw_cnt < gtd->ses->input->raw_len)
124 {
125 if (str_end >= 0 && str_cnt >= str_end)
126 {
127 break;
128 }
129
130 size = get_vt102_width(gtd->ses, >d->ses->input->buf[raw_cnt], &width);
131
132 if (str_cnt >= str_start)
133 {
134 ret_cnt += size;
135 }
136 raw_cnt += size;
137 str_cnt += width;
138 }
139 return ret_cnt;
140 }
141
inputline_raw_raw_len(int start,int end)142 int inputline_raw_raw_len(int start, int end)
143 {
144 if (start > end)
145 {
146 return 0;
147 }
148 return end - start;
149 }
150
inputline_cur_off(void)151 int inputline_cur_off(void)
152 {
153 int off;
154
155 off = gtd->ses->input->str_off;
156
157 off += gtd->ses->input->top_col - 1;
158
159 if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
160 {
161 off += 10;
162 }
163
164 return off;
165 }
166
inputline_rows(struct session * ses)167 int inputline_rows(struct session *ses)
168 {
169 if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
170 {
171 return 1;
172 }
173 return 1 + ses->input->bot_row - ses->input->top_row;
174 }
175
176 // Get string length of the input area
177
inputline_max_str_len(void)178 int inputline_max_str_len(void)
179 {
180 int result = 1 + gtd->ses->input->bot_col - gtd->ses->input->top_col;
181
182 result -= gtd->ses->input->str_off - 1;
183
184 if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
185 {
186 result -= 20;
187 }
188
189 return UMAX(1, result);
190 }
191
inputline_cur_str_len(void)192 int inputline_cur_str_len(void)
193 {
194 return inputline_str_str_len(gtd->ses->input->str_hid, gtd->ses->input->str_hid + inputline_max_str_len());
195 }
196
inputline_editor(void)197 int inputline_editor(void)
198 {
199 if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
200 {
201 return FALSE;
202 }
203
204 if (!HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_EDIT))
205 {
206 return FALSE;
207 }
208 return TRUE;
209 }
210
inputline_multiline(void)211 int inputline_multiline(void)
212 {
213 if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
214 {
215 return FALSE;
216 }
217
218 if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_EDIT))
219 {
220 return FALSE;
221 }
222
223 if (gtd->ses->input->top_row == gtd->ses->input->bot_row)
224 {
225 return FALSE;
226 }
227
228 return TRUE;
229 }
230
inputline_tab_valid(void)231 int inputline_tab_valid(void)
232 {
233 if (gtd->ses->input->raw_len == 0)
234 {
235 return FALSE;
236 }
237
238 if (gtd->ses->input->buf[gtd->ses->input->raw_len - 1] == ' ')
239 {
240 return FALSE;
241 }
242 return TRUE;
243 }
244
inputline_set_row(int row)245 void inputline_set_row(int row)
246 {
247 struct edit_data *edit = gtd->ses->input->edit;
248
249 if (row == gtd->ses->input->cur_row)
250 {
251 return;
252 }
253
254 if (inputline_editor())
255 {
256 str_cpy(&edit->line[edit->update]->str, gtd->ses->input->buf);
257
258 edit->update = URANGE(0, edit->update + (row - gtd->ses->input->cur_row), edit->used - 1);
259
260 inputline_set(edit->line[edit->update]->str, gtd->ses->input->str_pos);
261 }
262 gtd->ses->input->cur_row = row;
263 }
264
inputline_position(int col)265 void inputline_position(int col)
266 {
267 int size, width;
268
269 if (col == -1)
270 {
271 gtd->ses->input->raw_pos = gtd->ses->input->raw_len;
272 gtd->ses->input->str_pos = gtd->ses->input->str_len;
273
274 return;
275 }
276
277 gtd->ses->input->raw_pos = 0;
278 gtd->ses->input->str_pos = 0;
279
280 while (gtd->ses->input->raw_pos < gtd->ses->input->raw_len)
281 {
282 size = get_vt102_width(gtd->ses, >d->ses->input->buf[gtd->ses->input->raw_pos], &width);
283
284 if (gtd->ses->input->str_pos + width > col)
285 {
286 break;
287 }
288 gtd->ses->input->raw_pos += size;
289 gtd->ses->input->str_pos += width;
290 }
291
292 if (inputline_editor() && gtd->ses->input->str_len < col)
293 {
294 gtd->ses->input->str_pos = col;
295 }
296 }
297
inputline_insert(char * arg,int str_pos)298 void inputline_insert(char *arg, int str_pos)
299 {
300 int raw_len, str_len;
301
302 if (HAS_BIT(gtd->flags, TINTIN_FLAG_CHILDLOCK))
303 {
304 if (gtd->ses->input->raw_len > INPUT_SIZE)
305 {
306 tintin_printf2(gtd->ses, "#CONFIG CHILD LOCK: YOU ARE CONFINED TO %d BYTES OF INPUT.", INPUT_SIZE);
307
308 str_cpy(>d->ses->input->cut, "");
309
310 inputline_set("", -1);
311
312 return;
313 }
314 }
315
316 raw_len = strip_vt102_width(gtd->ses, arg, &str_len);
317
318 if (str_len && HAS_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT) && gtd->ses->input->raw_len != gtd->ses->input->raw_pos)
319 {
320 int cnt, loop;
321
322 cnt = UMAX(gtd->ses->input->str_pos, gtd->ses->input->str_len - str_len);
323
324 while (gtd->ses->input->str_len > cnt)
325 {
326 loop = gtd->ses->input->raw_len;
327
328 cursor_delete(gtd->ses, NULL);
329
330 if (loop == gtd->ses->input->raw_len)
331 {
332 tintin_printf2(gtd->ses, "inputline_insert: infinite loop detected.");
333 break;
334 }
335 }
336 }
337 str_ins(>d->ses->input->buf, gtd->ses->input->raw_pos, arg);
338
339 gtd->ses->input->raw_len += raw_len;
340 gtd->ses->input->str_len += str_len;
341
342 if (str_pos == -1)
343 {
344 gtd->ses->input->raw_pos += raw_len;
345 gtd->ses->input->str_pos += str_len;
346 }
347 }
348
inputline_set(char * arg,int str_pos)349 void inputline_set(char *arg, int str_pos)
350 {
351 int raw_len, str_len;
352
353 str_cpy(>d->ses->input->buf, arg);
354
355 raw_len = strip_vt102_width(gtd->ses, arg, &str_len);
356
357 gtd->ses->input->raw_len = raw_len;
358 gtd->ses->input->str_len = str_len;
359
360 gtd->ses->input->raw_pos = raw_len;
361 gtd->ses->input->str_pos = str_len;
362
363 inputline_position(str_pos);
364 }
365
inputline_cap(char * arg)366 void inputline_cap(char *arg)
367 {
368 int raw_len, str_len;
369
370 gtd->ses->input->raw_len = gtd->ses->input->raw_pos;
371 gtd->ses->input->str_len = gtd->ses->input->str_pos;
372
373 str_cap(>d->ses->input->buf, gtd->ses->input->raw_pos, arg);
374
375 raw_len = strip_vt102_width(gtd->ses, arg, &str_len);
376
377 gtd->ses->input->raw_len += raw_len;
378 gtd->ses->input->str_len += str_len;
379
380 gtd->ses->input->raw_pos += raw_len;
381 gtd->ses->input->str_pos += str_len;
382 }
383
384
385 // Get the position of the cursor
386
inputline_cur_row(void)387 int inputline_cur_row(void)
388 {
389 return gtd->ses->input->cur_row;
390 }
391
inputline_cur_col(void)392 int inputline_cur_col(void)
393 {
394 if (inputline_editor())
395 {
396 return inputline_cur_off() + gtd->ses->input->str_pos - gtd->ses->input->str_hid;
397 }
398
399 if (gtd->ses->input->top_row == gtd->ses->input->bot_row)
400 {
401 return inputline_cur_off() + gtd->ses->input->str_pos - gtd->ses->input->str_hid;
402 }
403 else
404 {
405 return inputline_cur_off() + gtd->ses->input->str_pos % inputline_max_str_len();
406 }
407 }
408
inputline_erase(void)409 void inputline_erase(void)
410 {
411 input_printf("\e[%dG\e[%dX", inputline_cur_off(), inputline_max_str_len());
412 }
413
414 // Get the maximum number of rows of the input region
415
inputline_max_row(void)416 int inputline_max_row(void)
417 {
418 return 1 + gtd->ses->input->bot_row - gtd->ses->input->top_row;
419 }
420
421 // Check for invalid characters.
422
inputline_str_chk(int offset,int totlen)423 int inputline_str_chk(int offset, int totlen)
424 {
425 int size;
426
427 while (offset < totlen)
428 {
429 if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_EUC))
430 {
431 if (is_euc_head(gtd->ses, >d->ses->input->buf[offset]))
432 {
433 size = get_euc_size(gtd->ses, >d->ses->input->buf[offset]);
434
435 if (size == 1 || offset + size > totlen)
436 {
437 return FALSE;
438 }
439 offset += size;
440 }
441 else
442 {
443 offset += 1;
444 }
445 }
446 else if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_UTF8))
447 {
448 if (is_utf8_head(>d->ses->input->buf[offset]))
449 {
450 size = get_utf8_size(>d->ses->input->buf[offset]);
451
452 if (size == 1 || offset + size > totlen)
453 {
454 return FALSE;
455 }
456 offset += size;
457 }
458 else
459 {
460 offset += 1;
461 }
462 }
463 else
464 {
465 return TRUE;
466 }
467 }
468 return TRUE;
469 }
470
DO_CURSOR(cursor_backspace)471 DO_CURSOR(cursor_backspace)
472 {
473 if (gtd->ses->input->raw_pos == 0)
474 {
475 if (inputline_editor())
476 {
477 if (gtd->ses->input->edit->update > 0)
478 {
479 cursor_move_up(ses, NULL);
480 cursor_end(ses, NULL);
481 cursor_delete(ses, NULL);
482
483 cursor_redraw_edit(ses, arg);
484 }
485 }
486 return;
487 }
488
489 cursor_move_left(ses, NULL);
490 cursor_delete(ses, arg);
491
492 modified_input();
493 }
494
DO_CURSOR(cursor_brace)495 DO_CURSOR(cursor_brace)
496 {
497 char arg1[BUFFER_SIZE];
498
499 arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
500
501 if (is_abbrev(arg1, "OPEN"))
502 {
503 inputline_insert("{", -1);
504 }
505 else if (is_abbrev(arg1, "CLOSE"))
506 {
507 inputline_insert("}", -1);
508 }
509 else
510 {
511 show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR {BRACE} {OPEN|CLOSE}");
512 }
513 cursor_redraw_line(ses, arg);
514
515 modified_input();
516 }
517
DO_CURSOR(cursor_buffer_down)518 DO_CURSOR(cursor_buffer_down)
519 {
520 if (inputline_editor())
521 {
522 int update = gtd->ses->input->edit->update;
523
524 if (update + 1 >= gtd->ses->input->edit->used)
525 {
526 return;
527 }
528
529 str_cpy(>d->ses->input->edit->line[update]->str, gtd->ses->input->buf);
530
531 update = UMIN(gtd->ses->input->edit->used - 1, update + UMAX(1, inputline_rows(gtd->ses) / 2));
532
533 inputline_set(gtd->ses->input->edit->line[update]->str, gtd->ses->input->str_pos);
534
535 gtd->ses->input->edit->update = update;
536
537 cursor_redraw_edit(ses, arg);
538
539 return;
540 }
541
542 command(ses, do_buffer, "down %s", arg);
543 }
544
DO_CURSOR(cursor_buffer_end)545 DO_CURSOR(cursor_buffer_end)
546 {
547 int update;
548
549 if (inputline_editor())
550 {
551 update = gtd->ses->input->edit->update;
552
553 if (update + 1 >= gtd->ses->input->edit->used && gtd->ses->input->cur_row == gtd->ses->input->bot_row)
554 {
555 return;
556 }
557
558 str_cpy(>d->ses->input->edit->line[update]->str, gtd->ses->input->buf);
559
560 update = gtd->ses->input->edit->used - 1;
561
562 inputline_set(gtd->ses->input->edit->line[update]->str, gtd->ses->input->str_pos);
563
564 gtd->ses->input->edit->update = update;
565
566 gtd->ses->input->cur_row = gtd->ses->input->bot_row;
567
568 cursor_redraw_edit(ses, arg);
569
570 return;
571 }
572 buffer_end(ses, "", "", "");
573 }
574
DO_CURSOR(cursor_buffer_home)575 DO_CURSOR(cursor_buffer_home)
576 {
577 if (inputline_editor())
578 {
579 int update = gtd->ses->input->edit->update;
580
581 if (update <= 0 && gtd->ses->input->cur_row == gtd->ses->input->top_row)
582 {
583 return;
584 }
585
586 str_cpy(>d->ses->input->edit->line[update]->str, gtd->ses->input->buf);
587
588 inputline_set(gtd->ses->input->edit->line[0]->str, gtd->ses->input->str_pos);
589
590 gtd->ses->input->edit->update = 0;
591
592 gtd->ses->input->cur_row = gtd->ses->input->top_row;
593
594 cursor_redraw_edit(ses, arg);
595
596 return;
597 }
598
599 buffer_home(ses, "", "", "");
600 }
601
DO_CURSOR(cursor_buffer_lock)602 DO_CURSOR(cursor_buffer_lock)
603 {
604 command(ses, do_buffer, "lock %s", arg);
605 }
606
DO_CURSOR(cursor_buffer_up)607 DO_CURSOR(cursor_buffer_up)
608 {
609 if (inputline_editor())
610 {
611 int update = gtd->ses->input->edit->update;
612
613 if (update <= 0)
614 {
615 return;
616 }
617
618 str_cpy(>d->ses->input->edit->line[update]->str, gtd->ses->input->buf);
619
620 update = UMAX(0, update - UMAX(1, inputline_rows(gtd->ses) / 2));
621
622 inputline_set(gtd->ses->input->edit->line[update]->str, gtd->ses->input->str_pos);
623
624 gtd->ses->input->edit->update = update;
625
626 cursor_redraw_edit(ses, arg);
627
628 return;
629 }
630
631 command(ses, do_buffer, "up %s", arg);
632 }
633
DO_CURSOR(cursor_page)634 DO_CURSOR(cursor_page)
635 {
636 char arg1[BUFFER_SIZE];
637
638 arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
639
640 if (is_abbrev(arg1, "DOWN"))
641 {
642 return cursor_buffer_down(ses, arg);
643 }
644 if (is_abbrev(arg1, "END"))
645 {
646 return cursor_buffer_end(ses, arg);
647 }
648 if (is_abbrev(arg1, "LOCK"))
649 {
650 return cursor_buffer_lock(ses, arg);
651 }
652 if (is_abbrev(arg1, "HOME"))
653 {
654 return cursor_buffer_home(ses, arg);
655 }
656 if (is_abbrev(arg1, "UP"))
657 {
658 return cursor_buffer_up(ses, arg);
659 }
660 show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR PAGE {DOWN|END|LOCK|HOME|UP}");
661 }
662
DO_CURSOR(cursor_check_line)663 DO_CURSOR(cursor_check_line)
664 {
665 if (arg == NULL)
666 {
667 return;
668 }
669
670 int str_max = inputline_max_str_len();
671
672 if (inputline_multiline())
673 {
674 if (gtd->ses->input->cur_row != gtd->ses->input->top_row + (gtd->ses->input->str_pos - gtd->ses->input->str_hid) / str_max)
675 {
676 return cursor_redraw_line(ses, "");
677 }
678
679 if (gtd->ses->input->str_hid && gtd->ses->input->str_pos - gtd->ses->input->str_hid < 1)
680 {
681 return cursor_redraw_line(ses, "");
682 }
683 }
684 else
685 {
686 if (gtd->ses->input->str_pos - gtd->ses->input->str_hid > str_max - 3)
687 {
688 return cursor_redraw_line(ses, "");
689 }
690
691 if (gtd->ses->input->str_hid && gtd->ses->input->str_pos - gtd->ses->input->str_hid < 3)
692 {
693 return cursor_redraw_line(ses, "");
694 }
695 }
696 gtd->ses->cur_col = inputline_cur_off() + gtd->ses->input->str_pos - gtd->ses->input->str_hid;
697 }
698
DO_CURSOR(cursor_check_line_modified)699 DO_CURSOR(cursor_check_line_modified)
700 {
701 int max, width;
702
703 if (gtd->ses->input->raw_len != str_len(gtd->ses->input->buf))
704 {
705 tintin_printf2(ses, "\e[1;31merror: cursor_check_line_modified1: raw: %d vs %d", gtd->ses->input->raw_len, str_len(gtd->ses->input->buf));
706 }
707
708 strip_vt102_width(gtd->ses, gtd->ses->input->buf, &width);
709
710 if (gtd->ses->input->str_len != width)
711 {
712 tintin_printf2(ses, "\e[1;31merror: cursor_check_line_modified2: str: %d vs %d", gtd->ses->input->str_len, width);
713 }
714
715 if (gtd->ses->input->str_pos > gtd->ses->input->str_len)
716 {
717 return cursor_end(ses, "");
718 }
719
720 max = inputline_max_str_len();
721
722 if (inputline_multiline())
723 {
724 if (gtd->ses->input->str_len / max != gtd->ses->input->str_pos / max)
725 {
726 return cursor_redraw_line(ses, "");
727 }
728
729 if (gtd->ses->input->str_pos % max == 0)
730 {
731 return cursor_redraw_line(ses, "");
732 }
733 }
734 return cursor_check_line(ses, "");
735 }
736
DO_CURSOR(cursor_clear_left)737 DO_CURSOR(cursor_clear_left)
738 {
739 if (gtd->ses->input->raw_pos == 0)
740 {
741 if (inputline_editor())
742 {
743 cursor_backspace(ses, arg);
744 }
745 return;
746 }
747
748 str_cpy_printf(>d->ses->input->cut, "%.*s", gtd->ses->input->raw_pos, gtd->ses->input->buf);
749
750 str_mov(>d->ses->input->buf, 0, gtd->ses->input->raw_pos);
751
752 gtd->ses->input->raw_len -= gtd->ses->input->raw_pos;
753 gtd->ses->input->str_len -= gtd->ses->input->str_pos;
754
755 gtd->ses->input->raw_pos = 0;
756 gtd->ses->input->str_pos = 0;
757
758 cursor_redraw_line(ses, "");
759
760 modified_input();
761 }
762
DO_CURSOR(cursor_remove_line)763 DO_CURSOR(cursor_remove_line)
764 {
765 str_cpy(>d->ses->input->cut, gtd->ses->input->buf);
766
767 inputline_set("", -1);
768
769 cursor_delete(ses, arg);
770 }
771
DO_CURSOR(cursor_clear_line)772 DO_CURSOR(cursor_clear_line)
773 {
774 if (inputline_editor())
775 {
776 return cursor_remove_line(ses, arg);
777 }
778
779 if (gtd->ses->input->raw_len == 0)
780 {
781 return;
782 }
783
784 str_cpy(>d->ses->input->cut, gtd->ses->input->buf);
785
786 inputline_set("", -1);
787
788 gtd->ses->input->str_hid = 0;
789
790 cursor_redraw_line(ses, "");
791
792 modified_input();
793 }
794
DO_CURSOR(cursor_clear_right)795 DO_CURSOR(cursor_clear_right)
796 {
797 if (gtd->ses->input->raw_pos == gtd->ses->input->raw_len)
798 {
799 if (inputline_editor())
800 {
801 cursor_delete(ses, arg);
802 }
803 return;
804 }
805
806 str_cpy(>d->ses->input->cut, >d->ses->input->buf[gtd->ses->input->raw_pos]);
807
808 str_cap(>d->ses->input->buf, gtd->ses->input->raw_pos, "");
809
810 gtd->ses->input->raw_len = gtd->ses->input->raw_pos;
811 gtd->ses->input->str_len = gtd->ses->input->str_pos;
812
813 // input_printf("\e[%dX", inputline_max_str_len() - inputline_str_str_len(gtd->ses->input->str_hid, gtd->ses->input->str_pos));
814
815 cursor_redraw_line(ses, "");
816
817 modified_input();
818 }
819
DO_CURSOR(cursor_convert_meta)820 DO_CURSOR(cursor_convert_meta)
821 {
822 SET_BIT(gtd->ses->input->flags, INPUT_FLAG_CONVERTMETACHAR);
823 }
824
DO_CURSOR(cursor_delete_or_exit)825 DO_CURSOR(cursor_delete_or_exit)
826 {
827 if (gtd->ses->input->raw_len == 0)
828 {
829 if (ses == gts)
830 {
831 command(ses, do_end, "");
832 }
833 else
834 {
835 command(ses, do_zap, "");
836 }
837 }
838 else
839 {
840 cursor_delete(ses, arg);
841 }
842 }
843
DO_CURSOR(cursor_delete)844 DO_CURSOR(cursor_delete)
845 {
846 int size, width;
847
848 if (gtd->ses->input->raw_len == 0)
849 {
850 if (inputline_editor())
851 {
852 if (gtd->ses->input->edit->update + 1 < gtd->ses->input->edit->used)
853 {
854 remove_line(gtd->ses->input->edit, gtd->ses->input->edit->update);
855
856 inputline_set(gtd->ses->input->edit->line[gtd->ses->input->edit->update]->str, 0);
857
858 cursor_redraw_edit(ses, arg);
859
860 modified_input();
861 }
862 }
863 return;
864 }
865
866 if (gtd->ses->input->raw_len == gtd->ses->input->raw_pos)
867 {
868 if (inputline_editor())
869 {
870 if (gtd->ses->input->edit->update + 1 < gtd->ses->input->edit->used)
871 {
872 inputline_insert(gtd->ses->input->edit->line[gtd->ses->input->edit->update + 1]->str, 0);
873
874 remove_line(gtd->ses->input->edit, gtd->ses->input->edit->update + 1);
875
876 cursor_redraw_edit(ses, arg);
877
878 modified_input();
879 }
880 }
881 return;
882 }
883
884 size = get_vt102_width(gtd->ses, >d->ses->input->buf[gtd->ses->input->raw_pos], &width);
885
886 gtd->ses->input->raw_len -= size;
887 gtd->ses->input->str_len -= width;
888
889 str_mov(>d->ses->input->buf, gtd->ses->input->raw_pos, gtd->ses->input->raw_pos + size);
890
891 if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
892 {
893 while (gtd->ses->input->raw_len > gtd->ses->input->raw_pos)
894 {
895 if (!is_utf8_head(>d->ses->input->buf[gtd->ses->input->raw_pos]))
896 {
897 break;
898 }
899 size = get_utf8_width(>d->ses->input->buf[gtd->ses->input->raw_pos], &width, NULL);
900
901 if (width)
902 {
903 break;
904 }
905 gtd->ses->input->raw_len -= size;
906
907 str_mov(>d->ses->input->buf, gtd->ses->input->raw_pos, gtd->ses->input->raw_pos + size);
908 }
909 }
910
911 if (gtd->ses->input->raw_len == gtd->ses->input->raw_pos)
912 {
913 input_printf("\e[1X");
914 cursor_check_line(ses, arg);
915 }
916 else
917 {
918 cursor_redraw_line(ses, "");
919 }
920 modified_input();
921 }
922
DO_CURSOR(cursor_delete_word_left)923 DO_CURSOR(cursor_delete_word_left)
924 {
925 int index_raw, index_str, span_raw, width;
926
927 if (gtd->ses->input->raw_pos == 0)
928 {
929 if (inputline_editor())
930 {
931 return cursor_backspace(ses, arg);
932 }
933 return;
934 }
935
936 index_raw = gtd->ses->input->raw_pos;
937 index_str = gtd->ses->input->str_pos;
938
939 while (gtd->ses->input->raw_pos > 0 && gtd->ses->input->buf[gtd->ses->input->raw_pos - 1] == ' ')
940 {
941 gtd->ses->input->raw_pos--;
942 }
943
944 while (gtd->ses->input->raw_pos > 0 && gtd->ses->input->buf[gtd->ses->input->raw_pos - 1] != ' ')
945 {
946 gtd->ses->input->raw_pos--;
947 }
948
949 span_raw = gtd->ses->input->raw_pos;
950
951 while (span_raw < index_raw)
952 {
953 span_raw += get_vt102_width(gtd->ses, >d->ses->input->buf[span_raw], &width);
954
955 gtd->ses->input->str_pos -= width;
956 }
957
958 str_cpy_printf(>d->ses->input->cut, "%.*s", index_raw - gtd->ses->input->raw_pos, >d->ses->input->buf[gtd->ses->input->raw_pos]);
959
960 str_mov(>d->ses->input->buf, gtd->ses->input->raw_pos, index_raw);
961
962 gtd->ses->input->raw_len -= index_raw - gtd->ses->input->raw_pos;
963 gtd->ses->input->str_len -= index_str - gtd->ses->input->str_pos;
964
965 cursor_redraw_line(ses, "");
966
967 modified_input();
968 }
969
970
DO_CURSOR(cursor_delete_word_right)971 DO_CURSOR(cursor_delete_word_right)
972 {
973 int index_raw, index_str, size, width;
974
975 if (gtd->ses->input->raw_pos == gtd->ses->input->raw_len)
976 {
977 if (inputline_editor())
978 {
979 return cursor_delete(ses, arg);
980 }
981 return;
982 }
983
984 index_raw = gtd->ses->input->raw_pos;
985 index_str = gtd->ses->input->str_pos;
986
987 while (gtd->ses->input->raw_pos < gtd->ses->input->raw_len && gtd->ses->input->buf[gtd->ses->input->raw_pos] == ' ')
988 {
989 gtd->ses->input->raw_pos++;
990 gtd->ses->input->str_pos++;
991 }
992
993 while (gtd->ses->input->raw_pos < gtd->ses->input->raw_len && gtd->ses->input->buf[gtd->ses->input->raw_pos] != ' ')
994 {
995 size = get_vt102_width(gtd->ses, >d->ses->input->buf[gtd->ses->input->raw_pos], &width);
996
997 gtd->ses->input->raw_pos += size;
998 gtd->ses->input->str_pos += width;
999 }
1000
1001 str_cpy_printf(>d->ses->input->cut, "%.*s", gtd->ses->input->raw_pos - index_raw, >d->ses->input->buf[gtd->ses->input->raw_pos]);
1002
1003 str_mov(>d->ses->input->buf, index_raw, gtd->ses->input->raw_pos);
1004
1005 gtd->ses->input->raw_len -= gtd->ses->input->raw_pos - index_raw;
1006 gtd->ses->input->str_len -= gtd->ses->input->str_pos - index_str;
1007
1008 gtd->ses->input->raw_pos = index_raw;
1009 gtd->ses->input->str_pos = index_str;
1010
1011 cursor_redraw_line(ses, "");
1012
1013 modified_input();
1014 }
1015
DO_CURSOR(cursor_echo)1016 DO_CURSOR(cursor_echo)
1017 {
1018 char arg1[BUFFER_SIZE];
1019
1020 arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
1021
1022 if (*arg1 == 0)
1023 {
1024 TOG_BIT(ses->telopts, TELOPT_FLAG_ECHO);
1025 }
1026 else if (!strcasecmp(arg1, "ON"))
1027 {
1028 SET_BIT(ses->telopts, TELOPT_FLAG_ECHO);
1029 }
1030 else if (!strcasecmp(arg1, "OFF"))
1031 {
1032 DEL_BIT(ses->telopts, TELOPT_FLAG_ECHO);
1033 }
1034 else
1035 {
1036 show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {ECHO} {ON|OFF}.");
1037 }
1038 }
1039
DO_CURSOR(cursor_end)1040 DO_CURSOR(cursor_end)
1041 {
1042 gtd->ses->input->raw_pos = gtd->ses->input->raw_len;
1043 gtd->ses->input->str_pos = inputline_raw_str_len(0, -1);
1044
1045 cursor_redraw_line(ses, arg);
1046 }
1047
DO_CURSOR(cursor_enter)1048 DO_CURSOR(cursor_enter)
1049 {
1050 int filesize;
1051
1052 push_call("cursor_enter(%p,%p)",ses,arg);
1053
1054 gtd->ses->input->str_hid = 0;
1055
1056 gtd->ses->input->raw_pos = 0;
1057 gtd->ses->input->str_pos = 0;
1058
1059 if (inputline_editor())
1060 {
1061 char *str1 = str_alloc_stack(0);
1062
1063 DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_EDIT);
1064
1065 str_cpy(>d->ses->input->edit->line[gtd->ses->input->edit->update]->str, gtd->ses->input->buf);
1066
1067 filesize = str_save_editor(gtd->ses->input->edit, &str1);
1068
1069 check_all_events(gtd->ses, EVENT_FLAG_INPUT, 0, 4, "EDIT FINISHED", gtd->ses->input->edit_name, ntos(gtd->ses->input->edit->used), ntos(filesize), str1);
1070
1071 if (*gtd->ses->input->edit_name)
1072 {
1073 check_all_events(gtd->ses, EVENT_FLAG_INPUT, 1, 4, "EDIT FINISHED %s", gtd->ses->input->edit_name, ntos(gtd->ses->input->edit->used), ntos(filesize), gtd->ses->input->edit_name, str1);
1074
1075 if (check_all_events(gtd->ses, EVENT_FLAG_CATCH, 1, 4, "CATCH EDIT FINISHED %s", gtd->ses->input->edit_name, gtd->ses->input->edit_name, ntos(gtd->ses->input->edit->used), ntos(filesize), str1))
1076 {
1077 cursor_enter_finish(ses, "");
1078
1079 pop_call();
1080 return;
1081 }
1082 }
1083
1084 if (check_all_events(gtd->ses, EVENT_FLAG_CATCH, 0, 4, "CATCH EDIT FINISHED", gtd->ses->input->edit_name, ntos(gtd->ses->input->edit->used), ntos(filesize), str1))
1085 {
1086 cursor_enter_finish(ses, "");
1087
1088 pop_call();
1089 return;
1090 }
1091 }
1092
1093 if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
1094 {
1095 struct listroot *root = ses->list[LIST_HISTORY];
1096
1097 if (root->update >= 0 && root->update < root->used)
1098 {
1099 inputline_set(root->list[root->update]->arg1, -1);
1100 }
1101
1102 DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH);
1103
1104 gtd->ses->input->str_hid = 0;
1105
1106 gtd->ses->input->raw_pos = 0;
1107 gtd->ses->input->str_pos = 0;
1108 }
1109 else if (*gtd->ses->input->buf == 0)
1110 {
1111 struct listroot *root = ses->list[LIST_HISTORY];
1112
1113 if (root->used && HAS_BIT(ses->config_flags, CONFIG_FLAG_REPEATENTER))
1114 {
1115 inputline_set(root->list[root->used - 1]->arg1, -1);
1116 }
1117 gtd->ses->input->str_hid = 0;
1118
1119 gtd->ses->input->raw_pos = 0;
1120 gtd->ses->input->str_pos = 0;
1121 }
1122
1123 if (HAS_BIT(gtd->ses->flags, SES_FLAG_SPLIT))
1124 {
1125 inputline_erase();
1126 }
1127 else
1128 {
1129 input_printf("\n");
1130 }
1131
1132 SET_BIT(gtd->flags, TINTIN_FLAG_PROCESSINPUT);
1133
1134 modified_input();
1135
1136 pop_call();
1137 return;
1138 }
1139
DO_CURSOR(cursor_soft_enter)1140 DO_CURSOR(cursor_soft_enter)
1141 {
1142 if (!inputline_editor())
1143 {
1144 // show_error(ses, LIST_COMMAND, "#ERROR: #CURSOR SOFT ENTER: YOU ARE NOT CURRENTLY EDITING.");
1145
1146 return cursor_enter(ses, arg);
1147 }
1148
1149 insert_line(gtd->ses->input->edit, gtd->ses->input->edit->update + 1, >d->ses->input->buf[gtd->ses->input->raw_pos]);
1150
1151 str_cap(>d->ses->input->buf, gtd->ses->input->raw_pos, "");
1152
1153 if (gtd->ses->input->raw_pos != gtd->ses->input->raw_len)
1154 {
1155 cursor_clear_right(ses, NULL);
1156 }
1157
1158 gtd->ses->input->str_hid = 0;
1159
1160 gtd->ses->input->raw_pos = 0;
1161 gtd->ses->input->str_pos = 0;
1162
1163 cursor_move_down(ses, "");
1164 }
1165
DO_CURSOR(cursor_enter_finish)1166 DO_CURSOR(cursor_enter_finish)
1167 {
1168 if (inputline_editor())
1169 {
1170 cursor_redraw_line(gtd->ses, "");
1171
1172 return;
1173 }
1174
1175 str_cpy(&ses->input->tmp, "");
1176 str_cpy(&ses->input->buf, "");
1177
1178 ses->input->raw_len = 0;
1179 ses->input->str_len = 0;
1180 ses->input->raw_pos = 0;
1181 ses->input->str_pos = 0;
1182
1183 ses->input->str_off = 1;
1184 ses->input->str_hid = 0;
1185
1186 DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_EDIT);
1187
1188 if (ses == gtd->ses && gtd->ses->scroll->line != -1)
1189 {
1190 cursor_check_line(gtd->ses, "");
1191
1192 buffer_end(gtd->ses, "", "", "");
1193 }
1194
1195 if (ses == gtd->ses && HAS_BIT(gtd->ses->flags, SES_FLAG_SPLIT))
1196 {
1197 cursor_redraw_line(gtd->ses, "");
1198 }
1199 }
1200
DO_CURSOR(cursor_flag)1201 DO_CURSOR(cursor_flag)
1202 {
1203 char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
1204
1205 arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
1206 arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
1207
1208 if (is_abbrev(arg1, "EOL"))
1209 {
1210 if (*arg2 == 0)
1211 {
1212 TOG_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF);
1213 }
1214 else if (!strcasecmp(arg2, "CR"))
1215 {
1216 SET_BIT(ses->telopts, TELOPT_FLAG_CR);
1217 DEL_BIT(ses->telopts, TELOPT_FLAG_LF);
1218 DEL_BIT(ses->telopts, TELOPT_FLAG_NUL);
1219 }
1220 else if (!strcasecmp(arg2, "LF"))
1221 {
1222 DEL_BIT(ses->telopts, TELOPT_FLAG_CR);
1223 SET_BIT(ses->telopts, TELOPT_FLAG_LF);
1224 DEL_BIT(ses->telopts, TELOPT_FLAG_NUL);
1225 }
1226 else if (!strcasecmp(arg2, "CRLF") || !strcasecmp(arg2, "ON"))
1227 {
1228 SET_BIT(ses->telopts, TELOPT_FLAG_CR);
1229 SET_BIT(ses->telopts, TELOPT_FLAG_LF);
1230 DEL_BIT(ses->telopts, TELOPT_FLAG_NUL);
1231 }
1232 else if (!strcasecmp(arg2, "CRNUL"))
1233 {
1234 SET_BIT(ses->telopts, TELOPT_FLAG_CR);
1235 DEL_BIT(ses->telopts, TELOPT_FLAG_LF);
1236 SET_BIT(ses->telopts, TELOPT_FLAG_NUL);
1237 }
1238 else if (!strcasecmp(arg2, "OFF"))
1239 {
1240 DEL_BIT(ses->telopts, TELOPT_FLAG_CR);
1241 DEL_BIT(ses->telopts, TELOPT_FLAG_LF);
1242 DEL_BIT(ses->telopts, TELOPT_FLAG_NUL);
1243 }
1244 else
1245 {
1246 show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {EOL} {CR|LF|CRLF|CRNUL|OFF}.");
1247 return;
1248 }
1249
1250 show_message(gtd->ses, LIST_COMMAND, "#CURSOR FLAG EOL HAS BEEN SET TO: %s",
1251 HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == 0 ? "OFF" :
1252 HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_NUL) == (TELOPT_FLAG_CR|TELOPT_FLAG_NUL) ? "CRNUL" :
1253 HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == TELOPT_FLAG_CR ? "CR" :
1254 HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == TELOPT_FLAG_LF ? "LF" : "CRLF");
1255
1256 return;
1257 }
1258
1259 if (is_abbrev(arg1, "ECHO"))
1260 {
1261 if (*arg2 == 0)
1262 {
1263 TOG_BIT(ses->telopts, TELOPT_FLAG_ECHO);
1264 }
1265 else if (!strcasecmp(arg2, "ON"))
1266 {
1267 SET_BIT(ses->telopts, TELOPT_FLAG_ECHO);
1268 }
1269 else if (!strcasecmp(arg2, "OFF"))
1270 {
1271 DEL_BIT(ses->telopts, TELOPT_FLAG_ECHO);
1272 }
1273 else
1274 {
1275 show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {ECHO} {ON|OFF}.");
1276 }
1277 return;
1278 }
1279
1280 if (is_abbrev(arg1, "INSERT") || is_abbrev(arg1, "OVERTYPE"))
1281 {
1282 if (*arg2 == 0)
1283 {
1284 TOG_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
1285 }
1286 else if (!strcasecmp(arg2, "ON"))
1287 {
1288 SET_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
1289 }
1290 else if (!strcasecmp(arg2, "OFF"))
1291 {
1292 DEL_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
1293 }
1294 else
1295 {
1296 show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {INSERT} {ON|OFF}.");
1297 }
1298 return;
1299 }
1300
1301 show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {ECHO|EOL|INSERT} {ON|OFF}.");
1302 }
1303
DO_CURSOR(cursor_get)1304 DO_CURSOR(cursor_get)
1305 {
1306 char arg1[BUFFER_SIZE];
1307
1308 arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
1309
1310 if (*arg1 == 0)
1311 {
1312 show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR GET {variable}");
1313 }
1314 else
1315 {
1316 set_nest_node_ses(ses, arg1, "%s", gtd->ses->input->buf);
1317 }
1318 }
1319
DO_CURSOR(cursor_history_next)1320 DO_CURSOR(cursor_history_next)
1321 {
1322 struct listroot *root = ses->list[LIST_HISTORY];
1323
1324 if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
1325 {
1326 if (root->update == root->used)
1327 {
1328 return;
1329 }
1330
1331 for (root->update++ ; root->update < root->used ; root->update++)
1332 {
1333 if (*gtd->ses->input->buf && find(ses, root->list[root->update]->arg1, gtd->ses->input->buf, SUB_NONE, REGEX_FLAG_NONE))
1334 {
1335 break;
1336 }
1337 }
1338
1339 if (root->update < root->used)
1340 {
1341 input_printf("\e[%dG\e[%dX ] %.*s",
1342 inputline_cur_off() + inputline_cur_str_len(),
1343 inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len(),
1344 UMAX(0, inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len() - 4),
1345 root->list[root->update]->arg1);
1346
1347 goto_pos(gtd->ses, inputline_cur_row(), inputline_cur_col());
1348 }
1349 return;
1350 }
1351
1352 if (!HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE))
1353 {
1354 return;
1355 }
1356
1357 if (root->update < root->used)
1358 {
1359 for (root->update++ ; root->update < root->used ; root->update++)
1360 {
1361 if (!strncmp(gtd->ses->input->tmp, root->list[root->update]->arg1, str_len(gtd->ses->input->tmp)))
1362 {
1363 break;
1364 }
1365 }
1366 }
1367
1368 if (root->update >= root->used)
1369 {
1370 DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE);
1371
1372 if (!strcmp(gtd->ses->input->buf, gtd->ses->input->tmp))
1373 {
1374 return;
1375 }
1376 inputline_set(gtd->ses->input->tmp, -1);
1377 }
1378 else
1379 {
1380 inputline_set(root->list[root->update]->arg1, -1);
1381 SET_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE);
1382 }
1383 cursor_end(ses, "");
1384 }
1385
DO_CURSOR(cursor_history_prev)1386 DO_CURSOR(cursor_history_prev)
1387 {
1388 struct listroot *root = ses->list[LIST_HISTORY];
1389
1390 if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
1391 {
1392 if (root->update <= 0)
1393 {
1394 return;
1395 }
1396
1397 if (root->update > root->used)
1398 {
1399 tintin_printf2(ses, "debug: cursor_history_prev %d > %d", root->update, root->used);
1400 return;
1401 }
1402
1403 for (root->update-- ; root->update >= 0 ; root->update--)
1404 {
1405 if (*gtd->ses->input->buf && find(ses, root->list[root->update]->arg1, gtd->ses->input->buf, SUB_NONE, REGEX_FLAG_NONE))
1406 {
1407 break;
1408 }
1409 }
1410
1411 if (root->update >= 0)
1412 {
1413 input_printf("\e[%dG\e[%dX ] %.*s",
1414 inputline_cur_off() + inputline_cur_str_len(),
1415 inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len(),
1416 UMAX(0, inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len() - 4),
1417 root->list[root->update]->arg1);
1418
1419 goto_pos(gtd->ses, inputline_cur_row(), inputline_cur_col());
1420 }
1421 return;
1422 }
1423
1424 if (root->update >= root->used || !HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE))
1425 {
1426 SET_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE);
1427
1428 str_cpy(>d->ses->input->tmp, gtd->ses->input->buf);
1429
1430 root->update = root->used - 1;
1431 }
1432 else if (root->update >= 0)
1433 {
1434 root->update--;
1435 }
1436
1437 while (root->update >= 0)
1438 {
1439 if (!strncmp(gtd->ses->input->tmp, root->list[root->update]->arg1, str_len(gtd->ses->input->tmp)))
1440 {
1441 break;
1442 }
1443 root->update--;
1444 }
1445
1446 if (root->update < 0)
1447 {
1448 if (!strcmp(gtd->ses->input->buf, gtd->ses->input->tmp))
1449 {
1450 return;
1451 }
1452 str_cpy(>d->ses->input->buf, gtd->ses->input->tmp);
1453 }
1454 else
1455 {
1456 str_cpy(>d->ses->input->buf, root->list[root->update]->arg1);
1457 }
1458
1459 gtd->ses->input->raw_len = strip_vt102_width(ses, gtd->ses->input->buf, >d->ses->input->str_len);
1460
1461 cursor_end(ses, "");
1462 }
1463
DO_CURSOR(cursor_history_search)1464 DO_CURSOR(cursor_history_search)
1465 {
1466 struct listroot *root = ses->list[LIST_HISTORY];
1467
1468 if (!HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
1469 {
1470 str_cpy(>d->ses->input->tmp, gtd->ses->input->buf);
1471
1472 inputline_set("", -1);
1473
1474 inputline_erase();
1475
1476 SET_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH);
1477
1478 root->update = -1;
1479
1480 input_printf("(search) [ ] \e[3D");
1481 }
1482 else
1483 {
1484 if (root->update >= 0 && root->update < root->used)
1485 {
1486 inputline_set(root->list[root->update]->arg1, -1);
1487 }
1488 else
1489 {
1490 inputline_set(gtd->ses->input->tmp, -1);
1491 }
1492
1493 DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH);
1494
1495 cursor_redraw_line(ses, "");
1496 }
1497 }
1498
DO_CURSOR(cursor_history_find)1499 DO_CURSOR(cursor_history_find)
1500 {
1501 struct listroot *root = ses->list[LIST_HISTORY];
1502
1503 push_call("cursor_history_find(%s)", gtd->ses->input->buf);
1504
1505 if (inputline_str_chk(0, gtd->ses->input->raw_len) == FALSE)
1506 {
1507 pop_call();
1508 return;
1509 }
1510
1511 if (*gtd->ses->input->buf == 0)
1512 {
1513 root->update = -1;
1514 }
1515 else
1516 {
1517 gtd->level->quiet++;
1518
1519 for (root->update = root->used - 1 ; root->update >= 0 ; root->update--)
1520 {
1521 if (find(ses, root->list[root->update]->arg1, gtd->ses->input->buf, SUB_NONE, REGEX_FLAG_NONE))
1522 {
1523 break;
1524 }
1525 }
1526 gtd->level->quiet--;
1527 }
1528
1529 if (root->update >= 0)
1530 {
1531 if (0 && gtd->ses->input->str_hid)
1532 {
1533 input_printf("\e[%dG\e[%dX ] %.*s",
1534 inputline_cur_off() + inputline_max_str_len(),
1535 7,
1536 7,
1537 root->list[root->update]->arg1);
1538 }
1539 else
1540 {
1541 input_printf("\e[%dG\e[%dX ] %.*s",
1542 inputline_cur_off() + inputline_cur_str_len(),
1543 inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len() + 20,
1544 UMAX(7, inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len() + 7),
1545 root->list[root->update]->arg1);
1546 }
1547 }
1548 else
1549 {
1550 input_printf("\e[%dG\e[%dX ]",
1551 inputline_cur_off() + inputline_cur_str_len(),
1552 inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len() + 20);
1553 }
1554 goto_pos(gtd->ses, inputline_cur_row(), inputline_cur_col());
1555
1556 pop_call();
1557 return;
1558 }
1559
DO_CURSOR(cursor_home)1560 DO_CURSOR(cursor_home)
1561 {
1562 if (gtd->ses->input->raw_pos == 0)
1563 {
1564 if (gtd->ses->input->str_pos)
1565 {
1566 gtd->ses->input->str_pos = 0;
1567
1568 return cursor_redraw_line(ses, arg);
1569 }
1570 return;
1571 }
1572
1573 input_printf("\e[%dD", gtd->ses->input->str_pos - gtd->ses->input->str_hid);
1574
1575 gtd->ses->input->raw_pos = 0;
1576 gtd->ses->input->str_pos = 0;
1577
1578 cursor_check_line(ses, arg);
1579 }
1580
DO_CURSOR(cursor_insert)1581 DO_CURSOR(cursor_insert)
1582 {
1583 char arg1[BUFFER_SIZE];
1584
1585 arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
1586
1587 if (*arg1 == 0)
1588 {
1589 TOG_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
1590 }
1591 else if (!strcasecmp(arg1, "ON"))
1592 {
1593 SET_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
1594 }
1595 else if (!strcasecmp(arg1, "OFF"))
1596 {
1597 DEL_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
1598 }
1599 else
1600 {
1601 show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {INSERT} {ON|OFF}.");
1602 }
1603 }
1604
DO_CURSOR(cursor_move_page_up)1605 DO_CURSOR(cursor_move_page_up)
1606 {
1607 int rows = UMAX(1, inputline_rows(gtd->ses) / 2);
1608
1609 DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH);
1610
1611 cursor_move_up(ses, ntos(rows));
1612 }
1613
DO_CURSOR(cursor_move_up)1614 DO_CURSOR(cursor_move_up)
1615 {
1616 int str_max, moves, update;
1617
1618 if (inputline_editor())
1619 {
1620 update = gtd->ses->input->edit->update;
1621
1622 if (update <= 0)
1623 {
1624 return;
1625 }
1626
1627 moves = arg ? URANGE(1, atoi(arg), update) : 1;
1628
1629 str_cpy(>d->ses->input->edit->line[update]->str, gtd->ses->input->buf);
1630
1631 inputline_set(gtd->ses->input->edit->line[update - moves]->str, gtd->ses->input->str_pos);
1632
1633 gtd->ses->input->edit->update -= moves;
1634
1635 gtd->ses->input->cur_row = UMAX(gtd->ses->input->top_row, gtd->ses->input->cur_row - moves);
1636
1637 cursor_redraw_edit(ses, arg);
1638
1639 return;
1640 }
1641
1642 if (!inputline_multiline())
1643 {
1644 return cursor_history_prev(ses, "");
1645 }
1646
1647 if (gtd->ses->input->str_pos == 0)
1648 {
1649 return cursor_history_prev(ses, "");
1650 }
1651
1652 moves = arg ? UMAX(1, atoi(arg)) : 1;
1653
1654 str_max = inputline_max_str_len();
1655
1656 while (moves--)
1657 {
1658 gtd->ses->input->str_pos = UMAX(0, gtd->ses->input->str_pos - str_max);
1659 }
1660
1661 gtd->ses->input->raw_pos = inputline_str_raw_len(0, gtd->ses->input->str_pos);
1662
1663 cursor_redraw_line(ses, arg);
1664 }
1665
DO_CURSOR(cursor_move_page_down)1666 DO_CURSOR(cursor_move_page_down)
1667 {
1668 int rows = UMAX(1, inputline_rows(gtd->ses) / 2);
1669
1670 DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH);
1671
1672 cursor_move_down(ses, ntos(rows));
1673 }
1674
DO_CURSOR(cursor_move_down)1675 DO_CURSOR(cursor_move_down)
1676 {
1677 int str_max, moves, update;
1678
1679 if (inputline_editor())
1680 {
1681 update = gtd->ses->input->edit->update;
1682
1683 if (update + 1 >= gtd->ses->input->edit->used)
1684 {
1685 return;
1686 }
1687
1688 moves = arg ? URANGE(1, atoi(arg), gtd->ses->input->edit->used - update - 1) : 1;
1689
1690 str_cpy(>d->ses->input->edit->line[update]->str, gtd->ses->input->buf);
1691
1692 inputline_set(gtd->ses->input->edit->line[update + moves]->str, gtd->ses->input->str_pos);
1693
1694 gtd->ses->input->edit->update += moves;
1695
1696 gtd->ses->input->cur_row = UMIN(gtd->ses->input->bot_row, gtd->ses->input->cur_row + moves);
1697
1698 cursor_redraw_edit(ses, arg);
1699
1700 return;
1701 }
1702
1703 if (!inputline_multiline())
1704 {
1705 return cursor_history_next(ses, "");
1706 }
1707
1708 if (gtd->ses->input->str_pos == gtd->ses->input->str_len)
1709 {
1710 return cursor_history_next(ses, "");
1711 }
1712
1713 str_max = inputline_max_str_len();
1714
1715 moves = arg ? UMAX(1, atoi(arg)) : 1;
1716
1717 while (moves--)
1718 {
1719 gtd->ses->input->str_pos = UMIN(gtd->ses->input->str_pos + str_max, gtd->ses->input->str_len);
1720 }
1721 gtd->ses->input->raw_pos = inputline_str_raw_len(0, gtd->ses->input->str_pos);
1722
1723 cursor_redraw_line(ses, arg);
1724 }
1725
DO_CURSOR(cursor_move_left)1726 DO_CURSOR(cursor_move_left)
1727 {
1728 int width;
1729
1730 if (gtd->ses->input->raw_pos > 0)
1731 {
1732 if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC))
1733 {
1734 gtd->ses->input->raw_pos--;
1735 gtd->ses->input->str_pos--;
1736 input_printf("\e[1D");
1737
1738 if (inputline_str_chk(0, gtd->ses->input->raw_pos) == FALSE)
1739 {
1740 gtd->ses->input->raw_pos--;
1741 gtd->ses->input->str_pos--;
1742 input_printf("\e[1D");
1743 }
1744 }
1745 else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
1746 {
1747 gtd->ses->input->raw_pos--;
1748
1749 if (gtd->ses->input->raw_pos > 0 && is_utf8_tail(>d->ses->input->buf[gtd->ses->input->raw_pos]))
1750 {
1751 do
1752 {
1753 gtd->ses->input->raw_pos--;
1754 }
1755 while (gtd->ses->input->raw_pos > 0 && is_utf8_tail(>d->ses->input->buf[gtd->ses->input->raw_pos]));
1756
1757 get_vt102_width(gtd->ses, >d->ses->input->buf[gtd->ses->input->raw_pos], &width);
1758
1759 if (width == 0)
1760 {
1761 return cursor_move_left(ses, "");
1762 }
1763 input_printf("\e[%dD", width);
1764 gtd->ses->input->str_pos -= width;
1765 }
1766 else
1767 {
1768 get_vt102_width(gtd->ses, >d->ses->input->buf[gtd->ses->input->raw_pos], &width);
1769
1770 gtd->ses->input->str_pos -= width;
1771
1772 input_printf("\e[%dD", width);
1773 }
1774 }
1775 else
1776 {
1777 do
1778 {
1779 gtd->ses->input->raw_pos--;
1780
1781 get_ascii_width(>d->ses->input->buf[gtd->ses->input->raw_pos], &width);
1782
1783 if (width)
1784 {
1785 gtd->ses->input->str_pos -= width;
1786 input_printf("\e[%dD", width);
1787 break;
1788 }
1789 }
1790 while (gtd->ses->input->raw_pos > 0);
1791 }
1792
1793 if (gtd->ses->input->raw_pos != gtd->ses->input->str_pos)
1794 {
1795 gtd->ses->input->raw_pos = inputline_str_raw_len(0, gtd->ses->input->str_pos);
1796 }
1797
1798 cursor_check_line(ses, "");
1799 }
1800 }
1801
DO_CURSOR(cursor_move_left_word)1802 DO_CURSOR(cursor_move_left_word)
1803 {
1804 int index_raw, span_raw, width;
1805
1806 if (gtd->ses->input->raw_pos == 0)
1807 {
1808 return;
1809 }
1810
1811 index_raw = gtd->ses->input->raw_pos;
1812
1813 while (gtd->ses->input->raw_pos > 0 && gtd->ses->input->buf[gtd->ses->input->raw_pos - 1] == ' ')
1814 {
1815 gtd->ses->input->raw_pos--;
1816 }
1817
1818 while (gtd->ses->input->raw_pos > 0 && gtd->ses->input->buf[gtd->ses->input->raw_pos - 1] != ' ')
1819 {
1820 gtd->ses->input->raw_pos--;
1821 }
1822
1823 span_raw = gtd->ses->input->raw_pos;
1824
1825 while (span_raw < index_raw)
1826 {
1827 span_raw += get_vt102_width(gtd->ses, >d->ses->input->buf[span_raw], &width);
1828
1829 gtd->ses->input->str_pos -= width;
1830 }
1831
1832 cursor_redraw_line(ses, "");
1833 }
1834
DO_CURSOR(cursor_move_right)1835 DO_CURSOR(cursor_move_right)
1836 {
1837 int size, width;
1838
1839 if (gtd->ses->input->raw_pos < gtd->ses->input->raw_len)
1840 {
1841 if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC))
1842 {
1843 gtd->ses->input->raw_pos += get_euc_width(gtd->ses, >d->ses->input->buf[gtd->ses->input->raw_pos], &width);
1844
1845 input_printf("\e[%dC", width);
1846
1847 gtd->ses->input->str_pos += width;
1848 }
1849 else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
1850 {
1851 gtd->ses->input->raw_pos += get_vt102_width(gtd->ses, >d->ses->input->buf[gtd->ses->input->raw_pos], &width);
1852
1853 if (width == 0)
1854 {
1855 return cursor_move_right(ses, arg);
1856 }
1857 input_printf("\e[%dC", width);
1858
1859 gtd->ses->input->str_pos += width;
1860
1861 while (gtd->ses->input->raw_pos < gtd->ses->input->raw_len)
1862 {
1863 if (!is_utf8_head(>d->ses->input->buf[gtd->ses->input->raw_pos]))
1864 {
1865 break;
1866 }
1867 size = get_utf8_width(>d->ses->input->buf[gtd->ses->input->raw_pos], &width, NULL);
1868
1869 if (width)
1870 {
1871 break;
1872 }
1873 gtd->ses->input->raw_pos += size;
1874 }
1875 }
1876 else
1877 {
1878 gtd->ses->input->raw_pos += get_ascii_width(>d->ses->input->buf[gtd->ses->input->raw_pos], &width);
1879
1880 input_printf("\e[1C");
1881
1882 gtd->ses->input->str_pos++;
1883 }
1884 }
1885
1886 cursor_check_line(ses, "");
1887 }
1888
DO_CURSOR(cursor_move_right_word)1889 DO_CURSOR(cursor_move_right_word)
1890 {
1891 int size, width;
1892
1893 if (gtd->ses->input->raw_pos == gtd->ses->input->raw_len)
1894 {
1895 return;
1896 }
1897
1898 while (gtd->ses->input->raw_pos < gtd->ses->input->raw_len && gtd->ses->input->buf[gtd->ses->input->raw_pos] == ' ')
1899 {
1900 gtd->ses->input->raw_pos++;
1901 gtd->ses->input->str_pos++;
1902 }
1903
1904 while (gtd->ses->input->raw_pos < gtd->ses->input->raw_len && gtd->ses->input->buf[gtd->ses->input->raw_pos] != ' ')
1905 {
1906 size = get_vt102_width(gtd->ses, >d->ses->input->buf[gtd->ses->input->raw_pos], &width);
1907
1908 gtd->ses->input->raw_pos += size;
1909 gtd->ses->input->str_pos += width;
1910 }
1911
1912 cursor_redraw_line(ses, "");
1913 }
1914
DO_CURSOR(cursor_paste_buffer)1915 DO_CURSOR(cursor_paste_buffer)
1916 {
1917 if (*gtd->ses->input->cut)
1918 {
1919 inputline_insert(gtd->ses->input->cut, -1);
1920
1921 cursor_redraw_line(ses, "");
1922
1923 modified_input();
1924 }
1925 }
1926
DO_CURSOR(cursor_position)1927 DO_CURSOR(cursor_position)
1928 {
1929 char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
1930 int row, col;
1931
1932 arg = sub_arg_in_braces(gtd->ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
1933 arg = sub_arg_in_braces(gtd->ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
1934
1935 if (*arg2 == 0)
1936 {
1937 col = gtd->ses->input->str_hid + get_col_index_arg(gtd->ses, arg1) - 1;
1938
1939 inputline_position(col);
1940
1941 return cursor_redraw_line(ses, arg);
1942 }
1943
1944 row = get_row_index_arg(gtd->ses, arg1);
1945 col = gtd->ses->input->str_hid + get_col_index_arg(gtd->ses, arg2) - 1;
1946
1947 if (row >= gtd->ses->input->top_row && row <= gtd->ses->input->bot_row)
1948 {
1949 if (inputline_rows(gtd->ses) > 1)
1950 {
1951 if (inputline_editor())
1952 {
1953 inputline_set_row(row);
1954 inputline_position(col);
1955
1956 return cursor_redraw_edit(ses, arg);
1957 }
1958
1959 gtd->ses->input->cur_row = gtd->ses->input->top_row;
1960
1961 while (gtd->ses->input->cur_row < row)
1962 {
1963 gtd->ses->input->cur_row++;
1964
1965 col += inputline_max_str_len();
1966 }
1967 }
1968 }
1969 inputline_position(col);
1970
1971 return cursor_redraw_line(ses, arg);
1972 }
1973
DO_CURSOR(cursor_macro)1974 DO_CURSOR(cursor_macro)
1975 {
1976 char arg1[BUFFER_SIZE];
1977
1978 arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
1979
1980 if (is_abbrev(arg1, "PRESERVE"))
1981 {
1982 SET_BIT(gtd->flags, TINTIN_FLAG_PRESERVEMACRO);
1983
1984 return;
1985 }
1986
1987 if (is_abbrev(arg1, "RESET"))
1988 {
1989 gtd->macro_buf[0] = 0;
1990
1991 return;
1992 }
1993
1994 show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR {MACRO} {PRESERVE|RESET}");
1995 }
1996
DO_CURSOR(cursor_preserve_macro)1997 DO_CURSOR(cursor_preserve_macro)
1998 {
1999 SET_BIT(gtd->flags, TINTIN_FLAG_PRESERVEMACRO);
2000 }
2001
DO_CURSOR(cursor_reset_macro)2002 DO_CURSOR(cursor_reset_macro)
2003 {
2004 gtd->macro_buf[0] = 0;
2005 }
2006
DO_CURSOR(cursor_redraw_input)2007 DO_CURSOR(cursor_redraw_input)
2008 {
2009 cursor_redraw_line(ses, "");
2010
2011 fflush(stdout);
2012 }
2013
DO_CURSOR(cursor_redraw_line)2014 DO_CURSOR(cursor_redraw_line)
2015 {
2016 push_call("cursor_redraw_line(%p,%p)",ses,arg);
2017
2018 if (arg == NULL) // avoid unnecessary redraws
2019 {
2020 pop_call();
2021 return;
2022 }
2023
2024 if (inputline_str_chk(0, gtd->ses->input->raw_len) == FALSE)
2025 {
2026 tintin_printf2(gtd->ses, "debug: cursor_redraw_line: corrupted utf-8 detected");
2027 pop_call();
2028 return;
2029 }
2030
2031 if (inputline_editor())
2032 {
2033 cursor_redraw_singleline(ses, "");
2034
2035 pop_call();
2036 return;
2037 }
2038
2039 if (inputline_multiline())
2040 {
2041 cursor_redraw_multiline(ses, "");
2042
2043 pop_call();
2044 return;
2045 }
2046
2047 cursor_redraw_singleline(ses, "");
2048
2049 pop_call();
2050 return;
2051 }
2052
DO_CURSOR(cursor_redraw_singleline)2053 DO_CURSOR(cursor_redraw_singleline)
2054 {
2055 int raw_len, raw_off, str_pos, str_max, str_len;
2056
2057 str_max = inputline_max_str_len();
2058
2059 // Center long lines of input
2060
2061 if (gtd->ses->input->str_pos > str_max - 3)
2062 {
2063 if (inputline_editor())
2064 {
2065 return cursor_redraw_edit(ses, arg);
2066 }
2067
2068 while (gtd->ses->input->str_pos - gtd->ses->input->str_hid > str_max - 3)
2069 {
2070 gtd->ses->input->str_hid += URANGE(1, 8, str_max);
2071 }
2072
2073 while (gtd->ses->input->str_pos - gtd->ses->input->str_hid < 3)
2074 {
2075 gtd->ses->input->str_hid -= URANGE(1, str_max - 8, gtd->ses->input->str_hid);
2076 }
2077 }
2078 else
2079 {
2080 if (gtd->ses->input->str_hid && gtd->ses->input->str_pos - gtd->ses->input->str_hid < 3)
2081 {
2082 if (inputline_editor())
2083 {
2084 return cursor_redraw_edit(ses, arg);
2085 }
2086
2087 gtd->ses->input->str_hid = 0;
2088 }
2089 }
2090
2091 inputline_erase();
2092
2093 // Print the entire thing
2094
2095 raw_len = inputline_str_raw_len(gtd->ses->input->str_hid, gtd->ses->input->str_hid + str_max - 1);
2096 // str_len = inputline_raw_str_len(0, -1);
2097 str_len = gtd->ses->input->str_len;
2098 raw_off = inputline_str_raw_len(0, gtd->ses->input->str_hid);
2099 str_pos = inputline_cur_off() + gtd->ses->input->str_pos - gtd->ses->input->str_hid;
2100
2101 if (inputline_editor() || str_max <= 4)
2102 {
2103 input_printf("%.*s", raw_len, >d->ses->input->buf[raw_off]);
2104 }
2105 else if (gtd->ses->input->str_hid)
2106 {
2107 if (gtd->ses->input->str_hid + str_max >= str_len)
2108 {
2109 input_printf("%.*s\e[%dG<", raw_len, >d->ses->input->buf[raw_off], inputline_cur_off());
2110 }
2111 else
2112 {
2113 input_printf("%.*s\e[%dG<\e[%dG>", raw_len, >d->ses->input->buf[raw_off], inputline_cur_off(), inputline_cur_off() - 1 + str_max);
2114 }
2115 }
2116 else
2117 {
2118 if (str_max >= inputline_raw_str_len(0, -1))
2119 {
2120 input_printf("%.*s", raw_len, >d->ses->input->buf[raw_off]);
2121 }
2122 else
2123 {
2124 input_printf("%.*s\e[%dG>", raw_len, >d->ses->input->buf[raw_off], inputline_cur_off() - 1 + str_max);
2125 }
2126 }
2127
2128 goto_pos(gtd->ses, inputline_cur_row(), str_pos);
2129
2130 if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
2131 {
2132 cursor_history_find(gtd->ses, "");
2133 }
2134 }
2135
DO_CURSOR(cursor_redraw_edit)2136 DO_CURSOR(cursor_redraw_edit)
2137 {
2138 int row, start, end, offset, raw_off, raw_width, str_max;
2139
2140 push_call("cursor_redraw_edit(%p,%p)",ses,arg);
2141
2142 if (arg == NULL)
2143 {
2144 pop_call();
2145 return;
2146 }
2147
2148 str_max = inputline_max_str_len();
2149
2150 // Center long lines of input
2151
2152 // Probably needs proper tab handling
2153
2154 if (gtd->ses->input->str_pos > str_max - 3)
2155 {
2156 while (gtd->ses->input->str_pos - gtd->ses->input->str_hid > str_max - 3)
2157 {
2158 gtd->ses->input->str_hid += URANGE(1, 8, str_max);
2159 }
2160
2161 while (gtd->ses->input->str_pos - gtd->ses->input->str_hid < 3)
2162 {
2163 gtd->ses->input->str_hid -= URANGE(1, str_max - 8, gtd->ses->input->str_hid);
2164 }
2165 }
2166 else
2167 {
2168 if (gtd->ses->input->str_hid && gtd->ses->input->str_pos - gtd->ses->input->str_hid < 3)
2169 {
2170 gtd->ses->input->str_hid = 0;
2171 }
2172 }
2173
2174 end = gtd->ses->input->bot_row - gtd->ses->input->cur_row;
2175
2176 while (end >= gtd->ses->input->edit->used - gtd->ses->input->edit->update)
2177 {
2178 gtd->ses->input->cur_row++;
2179
2180 end--;
2181 }
2182
2183 offset = gtd->ses->input->cur_row - gtd->ses->input->top_row;
2184
2185 start = gtd->ses->input->edit->update - offset;
2186
2187 while (start < 0)
2188 {
2189 gtd->ses->input->cur_row--;
2190
2191 start++;
2192 }
2193
2194
2195 for (row = gtd->ses->input->top_row ; row <= gtd->ses->input->bot_row ; row++)
2196 {
2197 goto_pos(gtd->ses, row, gtd->ses->input->top_col);
2198
2199 inputline_erase();
2200
2201 if (start >= gtd->ses->input->edit->used)
2202 {
2203 continue;
2204 }
2205
2206
2207 if (row == gtd->ses->input->cur_row)
2208 {
2209 raw_off = get_raw_off_str_range_raw_width(gtd->ses, gtd->ses->input->buf, gtd->ses->input->str_hid, gtd->ses->input->str_hid + str_max - 1, &raw_width);
2210
2211 input_printf("%.*s", raw_width, >d->ses->input->buf[raw_off]);
2212 }
2213 else
2214 {
2215 raw_off = get_raw_off_str_range_raw_width(gtd->ses, gtd->ses->input->edit->line[start]->str, gtd->ses->input->str_hid, gtd->ses->input->str_hid + str_max - 1, &raw_width);
2216
2217 input_printf("%.*s", raw_width, >d->ses->input->edit->line[start]->str[raw_off]);
2218 }
2219 start++;
2220 }
2221 /*
2222 goto_pos(gtd->ses, 1, 1);
2223
2224 printf("\e[1;31mcur_row %2d, cur_off %2d, str_hid %3d, str_pos %3d, str_max %3d, str_len %3d\e[0m",
2225 gtd->ses->input->cur_row,
2226 inputline_cur_off(),
2227 gtd->ses->input->str_hid,
2228 gtd->ses->input->str_pos,
2229 str_max,
2230 gtd->ses->input->str_len);
2231 */
2232 goto_pos(gtd->ses, inputline_cur_row(), inputline_cur_col());
2233
2234 pop_call();
2235 return;
2236 }
2237
DO_CURSOR(cursor_redraw_multiline)2238 DO_CURSOR(cursor_redraw_multiline)
2239 {
2240 int row, rows, str_max, hid, str_off, raw_off, raw_len;
2241
2242 str_max = inputline_max_str_len();
2243 rows = inputline_rows(gtd->ses);
2244
2245 if (gtd->ses->input->str_pos - gtd->ses->input->str_hid > rows * str_max - 1)
2246 {
2247 while (gtd->ses->input->str_pos - gtd->ses->input->str_hid > rows * str_max - 1)
2248 {
2249 gtd->ses->input->str_hid += rows * str_max;
2250 }
2251 }
2252 else if (gtd->ses->input->str_hid && gtd->ses->input->str_pos - gtd->ses->input->str_hid < 0)
2253 {
2254 while (gtd->ses->input->str_pos - gtd->ses->input->str_hid < 0)
2255 {
2256 gtd->ses->input->str_hid -= URANGE(1, rows * str_max, gtd->ses->input->str_hid);
2257 }
2258 }
2259
2260 hid = gtd->ses->input->str_hid;
2261
2262 if (hid)
2263 {
2264 str_off = gtd->ses->input->str_hid;
2265 raw_off = inputline_str_raw_len(0, str_off);
2266 }
2267 else
2268 {
2269 str_off = 0;
2270 raw_off = 0;
2271 }
2272
2273 for (row = gtd->ses->input->top_row ; row <= gtd->ses->input->bot_row ; row++)
2274 {
2275 goto_pos(gtd->ses, row, gtd->ses->input->top_col);
2276
2277 inputline_erase();
2278
2279 if (gtd->ses->input->str_len < str_off)
2280 {
2281 raw_len = 0;
2282 }
2283 else
2284 {
2285 raw_len = inputline_str_raw_len(str_off, str_off + str_max);
2286
2287 input_printf("%.*s", raw_len, >d->ses->input->buf[raw_off]);
2288 }
2289 str_off += str_max;
2290 raw_off += raw_len;
2291 }
2292
2293 gtd->ses->input->cur_row = gtd->ses->input->top_row + (gtd->ses->input->str_pos - gtd->ses->input->str_hid) / str_max;
2294
2295 /*
2296 goto_pos(gtd->ses, 1, 1);
2297
2298 printf("\e[1;31mcur_row %2d, top_row %2d, str_pos %3d, str_hid %3d, str_max %3d, str_len %3d\e[0m", gtd->ses->input->cur_row, gtd->ses->input->top_row, gtd->ses->input->str_pos, gtd->ses->input->str_hid, str_max, gtd->ses->input->str_len);
2299 */
2300 goto_pos(gtd->ses, inputline_cur_row(), inputline_cur_off() + gtd->ses->input->str_pos % str_max);
2301
2302 if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
2303 {
2304 cursor_history_find(gtd->ses, "");
2305 }
2306 }
2307
2308
2309 // like set, but sub escapes, unused
2310
DO_CURSOR(cursor_insert_line)2311 DO_CURSOR(cursor_insert_line)
2312 {
2313 char arg1[BUFFER_SIZE];
2314
2315 arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN|SUB_ESC);
2316
2317 if (*arg1 == 0)
2318 {
2319 return;
2320 }
2321
2322 inputline_insert(arg1, -1);
2323
2324 cursor_redraw_line(ses, "");
2325
2326 modified_input();
2327 }
2328
DO_CURSOR(cursor_set)2329 DO_CURSOR(cursor_set)
2330 {
2331 char arg1[BUFFER_SIZE];
2332
2333 arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
2334
2335 if (*arg1 == 0)
2336 {
2337 return;
2338 }
2339
2340 inputline_insert(arg1, -1);
2341
2342 cursor_redraw_line(ses, "");
2343
2344 modified_input();
2345 }
2346
DO_CURSOR(cursor_suspend)2347 DO_CURSOR(cursor_suspend)
2348 {
2349 if (!HAS_BIT(gtd->flags, TINTIN_FLAG_CHILDLOCK))
2350 {
2351 do_suspend(ses, arg, NULL, NULL, NULL, NULL);
2352 }
2353 }
2354
DO_CURSOR(cursor_info)2355 DO_CURSOR(cursor_info)
2356 {
2357 tintin_printf2(ses, "inputline_max_str_len(): %10d", inputline_max_str_len());
2358 tintin_printf2(ses, "inputline_cur_off(): %10d", inputline_cur_off());
2359 tintin_printf2(ses, "inputline_cur_str_len(): %10d", inputline_cur_str_len());
2360 tintin_printf2(ses, "inputline_rows(): %10d", inputline_rows(gtd->ses));
2361
2362 tintin_printf2(ses, "");
2363
2364 tintin_printf2(ses, "inputline_max_row(): %10d", inputline_max_row());
2365 tintin_printf2(ses, "inputline_cur_row(): %10d", inputline_cur_row());
2366 tintin_printf2(ses, "inputline_cur_col(): %10d", inputline_cur_col());
2367 tintin_printf2(ses, "inputline_cur_hid(): %10d", gtd->ses->input->str_hid);
2368
2369 tintin_printf2(ses, "");
2370
2371 tintin_printf2(ses, "input->raw_len: %10d", gtd->ses->input->raw_len);
2372 tintin_printf2(ses, "input->str_len: %10d", gtd->ses->input->str_len);
2373 tintin_printf2(ses, "input->raw_pos: %10d", gtd->ses->input->raw_pos);
2374 tintin_printf2(ses, "input->str_pos: %10d", gtd->ses->input->str_pos);
2375
2376 tintin_printf2(ses, "");
2377
2378 tintin_printf2(ses, "input->line_name: %s", gtd->ses->input->line_name);
2379 tintin_printf2(ses, "");
2380
2381 tintin_printf2(ses, "input->sav_top_row: %10d", gtd->ses->input->sav_top_row);
2382 tintin_printf2(ses, "input->sav_top_col: %10d", gtd->ses->input->sav_top_col);
2383 tintin_printf2(ses, "input->sav_bot_row: %10d", gtd->ses->input->sav_bot_row);
2384 tintin_printf2(ses, "input->sav_bot_col: %10d", gtd->ses->input->sav_bot_col);
2385
2386 tintin_printf2(ses, "");
2387
2388 tintin_printf2(ses, "input->top_row: %10d", gtd->ses->input->top_row);
2389 tintin_printf2(ses, "input->top_col: %10d", gtd->ses->input->top_col);
2390 tintin_printf2(ses, "input->bot_row: %10d", gtd->ses->input->bot_row);
2391 tintin_printf2(ses, "input->bot_col: %10d", gtd->ses->input->bot_col);
2392 }
2393
2394 /*
2395 original tab cycling by Ben Love
2396 */
2397
cursor_tab_add(int flag)2398 int cursor_tab_add(int flag)
2399 {
2400 struct listroot *tab_root = gtd->ses->list[LIST_TAB];
2401 struct listroot *cmd_root = gtd->ses->list[LIST_COMMAND];
2402 struct listnode *node;
2403 char *tail;
2404 int tail_len;
2405
2406 if (!HAS_BIT(tab_root->flags, LIST_FLAG_IGNORE))
2407 {
2408 tail = cmd_root->list[0]->arg1;
2409 tail_len = str_len(tail);
2410
2411 for (tab_root->update = 0 ; tab_root->update < tab_root->used ; tab_root->update++)
2412 {
2413 node = tab_root->list[tab_root->update];
2414
2415 if (HAS_BIT(flag, TAB_FLAG_CASELESS))
2416 {
2417 if (strncasecmp(node->arg1, tail, tail_len) != 0)
2418 {
2419 continue;
2420 }
2421 }
2422 else
2423 {
2424 if (*node->arg1 != *tail || strncmp(node->arg1, tail, tail_len) != 0)
2425 {
2426 continue;
2427 }
2428 }
2429
2430 if (search_node_list(cmd_root, node->arg1))
2431 {
2432 continue;
2433 }
2434 create_node_list(cmd_root, node->arg1, "", "", "");
2435
2436 if (node->shots && --node->shots == 0)
2437 {
2438 delete_node_list(gtd->ses, LIST_TAB, node);
2439 }
2440
2441 if (HAS_BIT(flag, TAB_FLAG_FORWARD))
2442 {
2443 return TRUE;
2444 }
2445 }
2446 }
2447 return FALSE;
2448 }
2449
cursor_scrollback_tab_add(int flag)2450 int cursor_scrollback_tab_add(int flag)
2451 {
2452 char tab[BUFFER_SIZE], buf[BUFFER_SIZE];
2453 struct listroot *root = gtd->ses->list[LIST_COMMAND];
2454 struct listnode *node;
2455 int scroll_cnt, tab_len, tail_len;
2456 char *ptb, *ptt, *tail;
2457
2458 tail = root->list[0]->arg1;
2459 tail_len = str_len(tail);
2460
2461 if (root->list[root->used - 1]->val32[0])
2462 {
2463 scroll_cnt = UMIN(root->list[root->used - 1]->val32[0], gtd->ses->scroll->used - 1);
2464 }
2465 else
2466 {
2467 scroll_cnt = gtd->ses->scroll->used - 1;
2468 }
2469
2470 for ( ; scroll_cnt > 0 ; scroll_cnt--)
2471 {
2472 if (HAS_BIT(gtd->ses->scroll->buffer[scroll_cnt]->flags, BUFFER_FLAG_GREP))
2473 {
2474 continue;
2475 }
2476
2477 strip_vt102_codes(gtd->ses->scroll->buffer[scroll_cnt]->str, buf);
2478
2479 ptb = buf;
2480
2481 while (*ptb)
2482 {
2483 while (*ptb && is_space(*ptb))
2484 {
2485 ptb++;
2486 }
2487
2488 if (HAS_BIT(flag, TAB_FLAG_CASELESS))
2489 {
2490 if (strncasecmp(ptb, tail, tail_len) != 0)
2491 {
2492 goto end;
2493 }
2494 }
2495 else
2496 {
2497 if (*ptb != *tail || strncmp(ptb, tail, tail_len) != 0)
2498 {
2499 goto end;
2500 }
2501 }
2502 ptt = tab;
2503
2504 for (tab_len = 0 ; tab_len < tail_len ; tab_len++)
2505 {
2506 *ptt++ = *ptb++;
2507 }
2508
2509 while (*ptb && *ptb != ' ')
2510 {
2511 switch (*ptb)
2512 {
2513 case ';':
2514 case '.':
2515 case ',':
2516 case '!':
2517 case '?':
2518 case ':':
2519 case '"':
2520 *ptt++ = 0;
2521 ptb++;
2522 break;
2523
2524 default:
2525 *ptt++ = *ptb++;
2526 break;
2527 }
2528 }
2529 *ptt = 0;
2530
2531 if (search_node_list(gtd->ses->list[LIST_COMMAND], tab))
2532 {
2533 goto end;
2534 }
2535
2536 node = create_node_list(gtd->ses->list[LIST_COMMAND], tab, "", "", "");
2537
2538 node->val32[0] = scroll_cnt;
2539
2540 if (HAS_BIT(flag, TAB_FLAG_FORWARD))
2541 {
2542 return TRUE;
2543 }
2544
2545 if (root->used > 100)
2546 {
2547 return FALSE;
2548 }
2549
2550 end:
2551
2552 while (*ptb && !is_space(*ptb))
2553 {
2554 ptb++;
2555 }
2556 }
2557 }
2558 return FALSE;
2559 }
2560
cursor_tab_forward(struct session * ses,int flag)2561 void cursor_tab_forward(struct session *ses, int flag)
2562 {
2563 struct listroot *root = gtd->ses->list[LIST_COMMAND];
2564 int tab_found;
2565
2566 if (inputline_tab_valid() == FALSE)
2567 {
2568 return;
2569 }
2570
2571 cursor_move_left_word(gtd->ses, "");
2572
2573 if (root->used == 0)
2574 {
2575 create_node_list(root, >d->ses->input->buf[gtd->ses->input->raw_pos], "", "", "");
2576 }
2577
2578 inputline_cap("");
2579
2580 tab_found = 0;
2581
2582 if (tab_found == 0 && HAS_BIT(flag, TAB_FLAG_LIST))
2583 {
2584 tab_found = cursor_tab_add(flag);
2585 }
2586
2587 if (tab_found == 0 && HAS_BIT(flag, TAB_FLAG_SCROLLBACK))
2588 {
2589 tab_found = cursor_scrollback_tab_add(flag);
2590 }
2591
2592 if (tab_found == 0 && HAS_BIT(flag, TAB_FLAG_DICTIONARY))
2593 {
2594 tab_found = cursor_dictionary_tab_add(flag);
2595 }
2596
2597 if (tab_found == 0)
2598 {
2599 inputline_insert(root->list[0]->arg1, -1);
2600
2601 kill_list(root);
2602 }
2603 else
2604 {
2605 inputline_insert(root->list[root->used - 1]->arg1, -1);
2606 }
2607 cursor_end(ses, "");
2608 }
2609
cursor_tab_backward(struct session * ses,int flag)2610 void cursor_tab_backward(struct session *ses, int flag)
2611 {
2612 struct listroot *root = ses->list[LIST_COMMAND];
2613
2614 if (inputline_tab_valid() == FALSE)
2615 {
2616 return;
2617 }
2618
2619 if (root->used)
2620 {
2621 delete_index_list(root, root->used - 1);
2622 }
2623
2624 cursor_move_left_word(gtd->ses, "");
2625
2626 if (root->used == 0)
2627 {
2628 create_node_list(root, >d->ses->input->buf[gtd->ses->input->raw_pos], "", "", "");
2629
2630 inputline_cap("");
2631
2632 if (HAS_BIT(flag, TAB_FLAG_LIST))
2633 {
2634 cursor_tab_add(flag);
2635 }
2636
2637 if (HAS_BIT(flag, TAB_FLAG_SCROLLBACK))
2638 {
2639 cursor_scrollback_tab_add(flag);
2640 }
2641
2642 if (HAS_BIT(flag, TAB_FLAG_DICTIONARY))
2643 {
2644 cursor_dictionary_tab_add(flag);
2645 }
2646 }
2647 else
2648 {
2649 inputline_cap("");
2650 }
2651
2652 inputline_insert(root->list[root->used - 1]->arg1, -1);
2653
2654 cursor_end(ses, "");
2655 }
2656
DO_CURSOR(cursor_tab)2657 DO_CURSOR(cursor_tab)
2658 {
2659 char arg1[BUFFER_SIZE];
2660 int flag = 0;
2661
2662 arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
2663
2664 while (*arg)
2665 {
2666 if (is_abbrev(arg1, "CASELESS"))
2667 {
2668 SET_BIT(flag, TAB_FLAG_CASELESS);
2669 }
2670 else if (is_abbrev(arg1, "COMPLETE"))
2671 {
2672 SET_BIT(flag, TAB_FLAG_COMPLETE);
2673 }
2674 else if (is_abbrev(arg1, "DICTIONARY"))
2675 {
2676 SET_BIT(flag, TAB_FLAG_DICTIONARY);
2677 }
2678 else if (is_abbrev(arg1, "LIST"))
2679 {
2680 SET_BIT(flag, TAB_FLAG_LIST);
2681 }
2682 else if (is_abbrev(arg1, "SCROLLBACK"))
2683 {
2684 SET_BIT(flag, TAB_FLAG_SCROLLBACK);
2685 }
2686
2687 arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
2688
2689 if (*arg == COMMAND_SEPARATOR)
2690 {
2691 arg++;
2692 }
2693 }
2694
2695 if (is_abbrev(arg1, "FORWARD"))
2696 {
2697 SET_BIT(flag, TAB_FLAG_FORWARD);
2698
2699 if (!HAS_BIT(flag, TAB_FLAG_COMPLETE) && inputline_editor())
2700 {
2701 sprintf(arg1, "%*s", gtd->ses->tab_width, "");
2702
2703 inputline_insert(arg1, -1);
2704
2705 return cursor_redraw_line(ses, arg);
2706 }
2707
2708 if (!HAS_BIT(flag, TAB_FLAG_DICTIONARY|TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
2709 {
2710 show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {DICTIONARY|LIST|SCROLLBACK} FORWARD");
2711 }
2712 else
2713 {
2714 cursor_tab_forward(ses, flag);
2715 }
2716 }
2717 else if (is_abbrev(arg1, "BACKWARD"))
2718 {
2719 SET_BIT(flag, TAB_FLAG_BACKWARD);
2720
2721 if (!HAS_BIT(flag, TAB_FLAG_COMPLETE) && inputline_editor())
2722 {
2723 sprintf(arg1, "%*s", gtd->ses->tab_width, "");
2724
2725 inputline_insert(arg1, 0);
2726
2727 return cursor_redraw_line(ses, arg);
2728 }
2729
2730 if (!HAS_BIT(flag, TAB_FLAG_DICTIONARY|TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
2731 {
2732 show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {DICTIONARY|LIST|SCROLLBACK} BACKWARD");
2733 }
2734 else
2735 {
2736 cursor_tab_backward(ses, flag);
2737 }
2738 }
2739 else
2740 {
2741 show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {DICTIONARY;LIST;SCROLLBACK} <BACKWARD|FORWARD>");
2742 }
2743 }
2744