Optimization of history save.
[midnight-commander.git] / lib / widget / input.c
blob48f4fa45a6457457c35b382e782ba0b37bda9433
1 /* Widgets for the Midnight Commander
3 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
4 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
6 Authors: 1994, 1995 Radek Doulik
7 1994, 1995 Miguel de Icaza
8 1995 Jakub Jelinek
9 1996 Andrej Borsenkow
10 1997 Norbert Warmuth
11 2009, 2010 Andrew Borodin
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29 /** \file input.c
30 * \brief Source: WInput widget
33 #include <config.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
40 #include "lib/global.h"
42 #include "lib/tty/tty.h"
43 #include "lib/tty/mouse.h"
44 #include "lib/tty/key.h" /* XCTRL and ALT macros */
45 #include "lib/fileloc.h"
46 #include "lib/skin.h"
47 #include "lib/strutil.h"
48 #include "lib/util.h"
49 #include "lib/keybind.h" /* global_keymap_t */
50 #include "lib/widget.h"
51 #include "lib/event.h" /* mc_event_raise() */
53 #include "input_complete.h"
55 /*** global variables ****************************************************************************/
57 int quote = 0;
59 const global_keymap_t *input_map;
61 /*** file scope macro definitions ****************************************************************/
63 #define LARGE_HISTORY_BUTTON 1
65 #ifdef LARGE_HISTORY_BUTTON
66 #define HISTORY_BUTTON_WIDTH 3
67 #else
68 #define HISTORY_BUTTON_WIDTH 1
69 #endif
71 #define should_show_history_button(in) \
72 (in->history != NULL && in->field_width > HISTORY_BUTTON_WIDTH * 2 + 1 \
73 && in->widget.owner != NULL)
75 /*** file scope type declarations ****************************************************************/
77 /*** file scope variables ************************************************************************/
79 /* Input widgets have a global kill ring */
80 /* Pointer to killed data */
81 static char *kill_buffer = NULL;
83 /*** file scope functions ************************************************************************/
84 /* --------------------------------------------------------------------------------------------- */
86 static void
87 draw_history_button (WInput * in)
89 char c;
90 gboolean disabled = (((Widget *) in)->options & W_DISABLED) != 0;
92 c = in->history->next ? (in->history->prev ? '|' : 'v') : '^';
93 widget_move (&in->widget, 0, in->field_width - HISTORY_BUTTON_WIDTH);
94 tty_setcolor (disabled ? DISABLED_COLOR : in->color[WINPUTC_HISTORY]);
95 #ifdef LARGE_HISTORY_BUTTON
97 Dlg_head *h;
98 h = in->widget.owner;
99 tty_print_string ("[ ]");
100 widget_move (&in->widget, 0, in->field_width - HISTORY_BUTTON_WIDTH + 1);
102 #endif
103 tty_print_char (c);
106 /* --------------------------------------------------------------------------------------------- */
108 static void
109 input_set_markers (WInput * in, long m1)
111 in->mark = m1;
114 /* --------------------------------------------------------------------------------------------- */
116 static void
117 input_mark_cmd (WInput * in, gboolean mark)
119 if (mark == 0)
121 in->highlight = FALSE;
122 input_set_markers (in, 0);
124 else
126 in->highlight = TRUE;
127 input_set_markers (in, in->point);
131 /* --------------------------------------------------------------------------------------------- */
133 static gboolean
134 input_eval_marks (WInput * in, long *start_mark, long *end_mark)
136 if (in->highlight)
138 *start_mark = min (in->mark, in->point);
139 *end_mark = max (in->mark, in->point);
140 return TRUE;
142 else
144 *start_mark = *end_mark = 0;
145 return FALSE;
149 /* --------------------------------------------------------------------------------------------- */
151 static void
152 delete_region (WInput * in, int x_first, int x_last)
154 int first = min (x_first, x_last);
155 int last = max (x_first, x_last);
156 size_t len;
158 input_mark_cmd (in, FALSE);
159 in->point = first;
160 last = str_offset_to_pos (in->buffer, last);
161 first = str_offset_to_pos (in->buffer, first);
162 len = strlen (&in->buffer[last]) + 1;
163 memmove (&in->buffer[first], &in->buffer[last], len);
164 in->charpoint = 0;
165 in->need_push = TRUE;
168 /* --------------------------------------------------------------------------------------------- */
170 static void
171 do_show_hist (WInput * in)
173 char *r;
175 r = history_show (&in->history, &in->widget);
176 if (r != NULL)
178 input_assign_text (in, r);
179 g_free (r);
183 /* --------------------------------------------------------------------------------------------- */
185 static void
186 push_history (WInput * in, const char *text)
188 /* input widget where urls with passwords are entered without any
189 vfs prefix */
190 const char *password_input_fields[] = {
191 " Link to a remote machine ",
192 " FTP to machine ",
193 " SMB link to machine "
195 const size_t ELEMENTS = (sizeof (password_input_fields) / sizeof (password_input_fields[0]));
197 char *t;
198 size_t i;
199 gboolean empty;
201 if (text == NULL)
202 return;
204 #ifdef ENABLE_NLS
205 for (i = 0; i < ELEMENTS; i++)
206 password_input_fields[i] = _(password_input_fields[i]);
207 #endif
209 t = g_strstrip (g_strdup (text));
210 empty = *t == '\0';
211 g_free (t);
212 t = g_strdup (empty ? "" : text);
214 if (in->history_name != NULL)
216 /* FIXME: It is the strange code. Rewrite is needed. */
218 const char *p = in->history_name + 3;
220 for (i = 0; i < ELEMENTS; i++)
221 if (strcmp (p, password_input_fields[i]) == 0)
222 break;
224 strip_password (t, i >= ELEMENTS);
227 in->history = list_append_unique (in->history, t);
228 in->need_push = FALSE;
231 /* --------------------------------------------------------------------------------------------- */
233 static void
234 move_buffer_backward (WInput * in, int start, int end)
236 int i, pos, len;
237 int str_len;
239 str_len = str_length (in->buffer);
240 if (start >= str_len || end > str_len + 1)
241 return;
243 pos = str_offset_to_pos (in->buffer, start);
244 len = str_offset_to_pos (in->buffer, end) - pos;
246 for (i = pos; in->buffer[i + len - 1]; i++)
247 in->buffer[i] = in->buffer[i + len];
250 /* --------------------------------------------------------------------------------------------- */
252 static cb_ret_t
253 insert_char (WInput * in, int c_code)
255 size_t i;
256 int res;
258 if (in->highlight)
260 long m1, m2;
261 if (input_eval_marks (in, &m1, &m2))
262 delete_region (in, m1, m2);
264 if (c_code == -1)
265 return MSG_NOT_HANDLED;
267 if (in->charpoint >= MB_LEN_MAX)
268 return MSG_HANDLED;
270 in->charbuf[in->charpoint] = c_code;
271 in->charpoint++;
273 res = str_is_valid_char (in->charbuf, in->charpoint);
274 if (res < 0)
276 if (res != -2)
277 in->charpoint = 0; /* broken multibyte char, skip */
278 return MSG_HANDLED;
281 in->need_push = TRUE;
282 if (strlen (in->buffer) + 1 + in->charpoint >= in->current_max_size)
284 /* Expand the buffer */
285 size_t new_length = in->current_max_size + in->field_width + in->charpoint;
286 char *narea = g_try_renew (char, in->buffer, new_length);
287 if (narea)
289 in->buffer = narea;
290 in->current_max_size = new_length;
294 if (strlen (in->buffer) + in->charpoint < in->current_max_size)
296 /* bytes from begin */
297 size_t ins_point = str_offset_to_pos (in->buffer, in->point);
298 /* move chars */
299 size_t rest_bytes = strlen (in->buffer + ins_point);
301 for (i = rest_bytes + 1; i > 0; i--)
302 in->buffer[ins_point + i + in->charpoint - 1] = in->buffer[ins_point + i - 1];
304 memcpy (in->buffer + ins_point, in->charbuf, in->charpoint);
305 in->point++;
308 in->charpoint = 0;
309 return MSG_HANDLED;
312 /* --------------------------------------------------------------------------------------------- */
314 static void
315 beginning_of_line (WInput * in)
317 in->point = 0;
318 in->charpoint = 0;
321 /* --------------------------------------------------------------------------------------------- */
323 static void
324 end_of_line (WInput * in)
326 in->point = str_length (in->buffer);
327 in->charpoint = 0;
330 /* --------------------------------------------------------------------------------------------- */
332 static void
333 backward_char (WInput * in)
335 const char *act;
337 act = in->buffer + str_offset_to_pos (in->buffer, in->point);
338 if (in->point > 0)
339 in->point -= str_cprev_noncomb_char (&act, in->buffer);
340 in->charpoint = 0;
343 /* --------------------------------------------------------------------------------------------- */
345 static void
346 forward_char (WInput * in)
348 const char *act;
350 act = in->buffer + str_offset_to_pos (in->buffer, in->point);
351 if (act[0] != '\0')
352 in->point += str_cnext_noncomb_char (&act);
353 in->charpoint = 0;
356 /* --------------------------------------------------------------------------------------------- */
358 static void
359 forward_word (WInput * in)
361 const char *p;
363 p = in->buffer + str_offset_to_pos (in->buffer, in->point);
364 while (p[0] != '\0' && (str_isspace (p) || str_ispunct (p)))
366 str_cnext_char (&p);
367 in->point++;
369 while (p[0] != '\0' && !str_isspace (p) && !str_ispunct (p))
371 str_cnext_char (&p);
372 in->point++;
376 /* --------------------------------------------------------------------------------------------- */
378 static void
379 backward_word (WInput * in)
381 const char *p, *p_tmp;
383 for (p = in->buffer + str_offset_to_pos (in->buffer, in->point);
384 (p != in->buffer) && (p[0] == '\0'); str_cprev_char (&p), in->point--);
386 while (p != in->buffer)
388 p_tmp = p;
389 str_cprev_char (&p);
390 if (!str_isspace (p) && !str_ispunct (p))
392 p = p_tmp;
393 break;
395 in->point--;
397 while (p != in->buffer)
399 str_cprev_char (&p);
400 if (str_isspace (p) || str_ispunct (p))
401 break;
403 in->point--;
407 /* --------------------------------------------------------------------------------------------- */
409 static void
410 backward_delete (WInput * in)
412 const char *act = in->buffer + str_offset_to_pos (in->buffer, in->point);
413 int start;
415 if (in->point == 0)
416 return;
418 start = in->point - str_cprev_noncomb_char (&act, in->buffer);
419 move_buffer_backward (in, start, in->point);
420 in->charpoint = 0;
421 in->need_push = TRUE;
422 in->point = start;
425 /* --------------------------------------------------------------------------------------------- */
427 static void
428 delete_char (WInput * in)
430 const char *act;
431 int end = in->point;
433 act = in->buffer + str_offset_to_pos (in->buffer, in->point);
434 end += str_cnext_noncomb_char (&act);
436 move_buffer_backward (in, in->point, end);
437 in->charpoint = 0;
438 in->need_push = TRUE;
441 /* --------------------------------------------------------------------------------------------- */
443 static void
444 copy_region (WInput * in, int x_first, int x_last)
446 int first = min (x_first, x_last);
447 int last = max (x_first, x_last);
449 if (last == first)
451 /* Copy selected files to clipboard */
452 mc_event_raise (MCEVENT_GROUP_FILEMANAGER, "panel_save_curent_file_to_clip_file", NULL);
453 /* try use external clipboard utility */
454 mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
455 return;
458 g_free (kill_buffer);
460 first = str_offset_to_pos (in->buffer, first);
461 last = str_offset_to_pos (in->buffer, last);
463 kill_buffer = g_strndup (in->buffer + first, last - first);
465 mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_text_to_file", kill_buffer);
466 /* try use external clipboard utility */
467 mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", NULL);
470 /* --------------------------------------------------------------------------------------------- */
472 static void
473 kill_word (WInput * in)
475 int old_point = in->point;
476 int new_point;
478 forward_word (in);
479 new_point = in->point;
480 in->point = old_point;
482 delete_region (in, old_point, new_point);
483 in->need_push = TRUE;
484 in->charpoint = 0;
487 /* --------------------------------------------------------------------------------------------- */
489 static void
490 back_kill_word (WInput * in)
492 int old_point = in->point;
493 int new_point;
495 backward_word (in);
496 new_point = in->point;
497 in->point = old_point;
499 delete_region (in, old_point, new_point);
500 in->need_push = TRUE;
503 /* --------------------------------------------------------------------------------------------- */
505 static void
506 yank (WInput * in)
508 if (kill_buffer != NULL)
510 char *p;
512 in->charpoint = 0;
513 for (p = kill_buffer; *p != '\0'; p++)
514 insert_char (in, *p);
515 in->charpoint = 0;
519 /* --------------------------------------------------------------------------------------------- */
521 static void
522 kill_line (WInput * in)
524 int chp;
526 chp = str_offset_to_pos (in->buffer, in->point);
527 g_free (kill_buffer);
528 kill_buffer = g_strdup (&in->buffer[chp]);
529 in->buffer[chp] = '\0';
530 in->charpoint = 0;
533 /* --------------------------------------------------------------------------------------------- */
535 static void
536 clear_line (WInput * in)
538 in->need_push = 1;
539 in->buffer[0] = '\0';
540 in->point = 0;
541 in->mark = 0;
542 in->highlight = FALSE;
543 in->charpoint = 0;
546 static void
547 ins_from_clip (WInput * in)
549 char *p = NULL;
550 ev_clipboard_text_from_file_t event_data;
552 /* try use external clipboard utility */
553 mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_file_from_ext_clip", NULL);
556 event_data.text = &p;
557 mc_event_raise (MCEVENT_GROUP_CORE, "clipboard_text_from_file", &event_data);
558 if (event_data.ret)
560 char *pp;
562 for (pp = p; *pp != '\0'; pp++)
563 insert_char (in, *pp);
565 g_free (p);
569 /* --------------------------------------------------------------------------------------------- */
571 static void
572 hist_prev (WInput * in)
574 GList *prev;
576 if (in->history == NULL)
577 return;
579 if (in->need_push)
580 push_history (in, in->buffer);
582 prev = g_list_previous (in->history);
583 if (prev != NULL)
585 in->history = prev;
586 input_assign_text (in, (char *) prev->data);
587 in->need_push = FALSE;
591 /* --------------------------------------------------------------------------------------------- */
593 static void
594 hist_next (WInput * in)
596 if (in->need_push)
598 push_history (in, in->buffer);
599 input_assign_text (in, "");
600 return;
603 if (in->history == NULL)
604 return;
606 if (in->history->next == NULL)
607 input_assign_text (in, "");
608 else
610 in->history = g_list_next (in->history);
611 input_assign_text (in, (char *) in->history->data);
612 in->need_push = FALSE;
616 /* --------------------------------------------------------------------------------------------- */
618 static void
619 port_region_marked_for_delete (WInput * in)
621 in->buffer[0] = '\0';
622 in->point = 0;
623 in->first = FALSE;
624 in->charpoint = 0;
627 /* --------------------------------------------------------------------------------------------- */
629 static cb_ret_t
630 input_execute_cmd (WInput * in, unsigned long command)
632 cb_ret_t res = MSG_HANDLED;
634 /* a highlight command like shift-arrow */
635 if (command == CK_MarkLeft || command == CK_MarkRight ||
636 command == CK_MarkToWordBegin || command == CK_MarkToWordEnd ||
637 command == CK_MarkToHome || command == CK_MarkToEnd)
639 if (!in->highlight)
641 input_mark_cmd (in, FALSE); /* clear */
642 input_mark_cmd (in, TRUE); /* marking on */
646 switch (command)
648 case CK_WordRight:
649 case CK_WordLeft:
650 case CK_Right:
651 case CK_Left:
652 if (in->highlight)
653 input_mark_cmd (in, FALSE);
656 switch (command)
658 case CK_Home:
659 case CK_MarkToHome:
660 beginning_of_line (in);
661 break;
662 case CK_End:
663 case CK_MarkToEnd:
664 end_of_line (in);
665 break;
666 case CK_Left:
667 case CK_MarkLeft:
668 backward_char (in);
669 break;
670 case CK_WordLeft:
671 case CK_MarkToWordBegin:
672 backward_word (in);
673 break;
674 case CK_Right:
675 case CK_MarkRight:
676 forward_char (in);
677 break;
678 case CK_WordRight:
679 case CK_MarkToWordEnd:
680 forward_word (in);
681 break;
682 case CK_BackSpace:
683 if (in->highlight)
685 long m1, m2;
686 if (input_eval_marks (in, &m1, &m2))
687 delete_region (in, m1, m2);
689 else
690 backward_delete (in);
691 break;
692 case CK_Delete:
693 if (in->first)
694 port_region_marked_for_delete (in);
695 else if (in->highlight)
697 long m1, m2;
698 if (input_eval_marks (in, &m1, &m2))
699 delete_region (in, m1, m2);
701 else
702 delete_char (in);
703 break;
704 case CK_DeleteToWordEnd:
705 kill_word (in);
706 break;
707 case CK_DeleteToWordBegin:
708 back_kill_word (in);
709 break;
710 case CK_Mark:
711 input_mark_cmd (in, TRUE);
712 break;
713 case CK_Remove:
714 delete_region (in, in->point, in->mark);
715 break;
716 case CK_DeleteToEnd:
717 kill_line (in);
718 break;
719 case CK_Clear:
720 clear_line (in);
721 break;
722 case CK_Store:
723 copy_region (in, in->mark, in->point);
724 break;
725 case CK_Cut:
726 copy_region (in, in->mark, in->point);
727 delete_region (in, in->point, in->mark);
728 break;
729 case CK_Yank:
730 yank (in);
731 break;
732 case CK_Paste:
733 ins_from_clip (in);
734 break;
735 case CK_HistoryPrev:
736 hist_prev (in);
737 break;
738 case CK_HistoryNext:
739 hist_next (in);
740 break;
741 case CK_History:
742 do_show_hist (in);
743 break;
744 case CK_Complete:
745 complete (in);
746 break;
747 default:
748 res = MSG_NOT_HANDLED;
751 if (command != CK_MarkLeft && command != CK_MarkRight &&
752 command != CK_MarkToWordBegin && command != CK_MarkToWordEnd &&
753 command != CK_MarkToHome && command != CK_MarkToEnd)
754 in->highlight = FALSE;
756 return res;
759 /* --------------------------------------------------------------------------------------------- */
761 /* "history_save" event handler */
762 static gboolean
763 input_save_history (const gchar * event_group_name, const gchar * event_name,
764 gpointer init_data, gpointer data)
766 WInput *in = (WInput *) init_data;
768 (void) event_group_name;
769 (void) event_name;
771 if (in->history != NULL && !in->is_password && (((Widget *) in)->owner->ret_value != B_CANCEL))
773 ev_history_load_save_t *ev = (ev_history_load_save_t *) data;
775 if (in->need_push)
776 push_history (in, in->buffer);
777 history_save (ev->cfg, in->history_name, in->history);
780 return TRUE;
783 /* --------------------------------------------------------------------------------------------- */
785 static void
786 input_destroy (WInput * in)
788 if (in == NULL)
790 fprintf (stderr, "Internal error: null Input *\n");
791 exit (EXIT_FAILURE);
794 input_clean (in);
796 /* clean history */
797 if (in->history != NULL)
799 /* history is already saved before this moment */
800 in->history = g_list_first (in->history);
801 g_list_foreach (in->history, (GFunc) g_free, NULL);
802 g_list_free (in->history);
805 g_free (in->buffer);
806 input_free_completions (in);
807 g_free (in->history_name);
809 g_free (kill_buffer);
810 kill_buffer = NULL;
813 /* --------------------------------------------------------------------------------------------- */
815 static int
816 input_event (Gpm_Event * event, void *data)
818 WInput *in = (WInput *) data;
820 if ((event->type & GPM_DOWN) != 0)
822 in->first = FALSE;
823 input_mark_cmd (in, FALSE);
826 if ((event->type & (GPM_DOWN | GPM_DRAG)) != 0)
828 dlg_select_widget (in);
830 if (event->x >= in->field_width - HISTORY_BUTTON_WIDTH + 1
831 && should_show_history_button (in))
832 do_show_hist (in);
833 else
835 in->point = str_length (in->buffer);
836 if (event->x + in->term_first_shown - 1 < str_term_width1 (in->buffer))
837 in->point = str_column_to_pos (in->buffer, event->x + in->term_first_shown - 1);
839 input_update (in, TRUE);
841 /* A lone up mustn't do anything */
842 if (in->highlight && (event->type & (GPM_UP | GPM_DRAG)) != 0)
843 return MOU_NORMAL;
845 if ((event->type & GPM_DRAG) == 0)
846 input_mark_cmd (in, TRUE);
848 return MOU_NORMAL;
851 /* --------------------------------------------------------------------------------------------- */
852 /*** public functions ****************************************************************************/
853 /* --------------------------------------------------------------------------------------------- */
855 /** Create new instance of WInput object.
856 * @param y Y coordinate
857 * @param x X coordinate
858 * @param input_colors Array of used colors
859 * @param width Widget width
860 * @param def_text Default text filled in widget
861 * @param histname Name of history
862 * @param completion_flags Flags for specify type of completions
863 * @returns WInput object
865 WInput *
866 input_new (int y, int x, const int *input_colors, int width, const char *def_text,
867 const char *histname, input_complete_t completion_flags)
869 WInput *in = g_new (WInput, 1);
870 size_t initial_buffer_len;
872 init_widget (&in->widget, y, x, 1, width, input_callback, input_event);
874 /* history setup */
875 in->history_name = NULL;
876 in->history = NULL;
877 if ((histname != NULL) && (*histname != '\0'))
879 in->history_name = g_strdup (histname);
880 in->history = history_get (histname);
883 if (def_text == NULL)
884 def_text = "";
885 else if (def_text == INPUT_LAST_TEXT)
887 if ((in->history != NULL) && (in->history->data != NULL))
888 def_text = (char *) in->history->data;
889 else
890 def_text = "";
893 initial_buffer_len = strlen (def_text);
894 initial_buffer_len = 1 + max ((size_t) width, initial_buffer_len);
895 in->widget.options |= W_IS_INPUT;
896 in->completions = NULL;
897 in->completion_flags = completion_flags;
898 in->current_max_size = initial_buffer_len;
899 in->buffer = g_new (char, initial_buffer_len);
901 memmove (in->color, input_colors, sizeof (input_colors_t));
903 in->field_width = width;
904 in->first = TRUE;
905 in->highlight = FALSE;
906 in->term_first_shown = 0;
907 in->disable_update = 0;
908 in->mark = 0;
909 in->need_push = TRUE;
910 in->is_password = FALSE;
912 strcpy (in->buffer, def_text);
913 in->point = str_length (in->buffer);
914 in->charpoint = 0;
916 return in;
919 /* --------------------------------------------------------------------------------------------- */
921 cb_ret_t
922 input_callback (Widget * w, widget_msg_t msg, int parm)
924 WInput *in = (WInput *) w;
925 cb_ret_t v;
927 switch (msg)
929 case WIDGET_INIT:
930 /* subscribe to "history_save" event */
931 mc_event_add (w->owner->event_group, MCEVENT_HISTORY_SAVE, input_save_history, w, NULL);
932 return MSG_HANDLED;
934 case WIDGET_KEY:
935 if (parm == XCTRL ('q'))
937 quote = 1;
938 v = input_handle_char (in, ascii_alpha_to_cntrl (tty_getch ()));
939 quote = 0;
940 return v;
943 /* Keys we want others to handle */
944 if (parm == KEY_UP || parm == KEY_DOWN || parm == ESC_CHAR
945 || parm == KEY_F (10) || parm == '\n')
946 return MSG_NOT_HANDLED;
948 /* When pasting multiline text, insert literal Enter */
949 if ((parm & ~KEY_M_MASK) == '\n')
951 quote = 1;
952 v = input_handle_char (in, '\n');
953 quote = 0;
954 return v;
957 return input_handle_char (in, parm);
959 case WIDGET_COMMAND:
960 return input_execute_cmd (in, parm);
962 case WIDGET_FOCUS:
963 case WIDGET_UNFOCUS:
964 case WIDGET_DRAW:
965 input_update (in, FALSE);
966 return MSG_HANDLED;
968 case WIDGET_CURSOR:
969 widget_move (&in->widget, 0, str_term_width2 (in->buffer, in->point)
970 - in->term_first_shown);
971 return MSG_HANDLED;
973 case WIDGET_DESTROY:
974 /* unsubscribe from "history_save" event */
975 mc_event_del (w->owner->event_group, MCEVENT_HISTORY_SAVE, input_save_history, w);
976 input_destroy (in);
977 return MSG_HANDLED;
979 default:
980 return default_proc (msg, parm);
984 /* --------------------------------------------------------------------------------------------- */
986 /** Get default colors for WInput widget.
987 * @returns default colors
989 const int *
990 input_get_default_colors (void)
992 static input_colors_t standart_colors;
994 standart_colors[WINPUTC_MAIN] = INPUT_COLOR;
995 standart_colors[WINPUTC_MARK] = INPUT_MARK_COLOR;
996 standart_colors[WINPUTC_UNCHANGED] = INPUT_UNCHANGED_COLOR;
997 standart_colors[WINPUTC_HISTORY] = INPUT_HISTORY_COLOR;
999 return standart_colors;
1002 /* --------------------------------------------------------------------------------------------- */
1004 void
1005 input_set_origin (WInput * in, int x, int field_width)
1007 in->widget.x = x;
1008 in->field_width = in->widget.cols = field_width;
1009 input_update (in, FALSE);
1012 /* --------------------------------------------------------------------------------------------- */
1014 cb_ret_t
1015 input_handle_char (WInput * in, int key)
1017 cb_ret_t v;
1018 unsigned long command;
1020 v = MSG_NOT_HANDLED;
1022 if (quote != 0)
1024 input_free_completions (in);
1025 v = insert_char (in, key);
1026 input_update (in, TRUE);
1027 quote = 0;
1028 return v;
1031 command = keybind_lookup_keymap_command (input_map, key);
1033 if (command == CK_IgnoreKey)
1035 if (key > 255)
1036 return MSG_NOT_HANDLED;
1037 if (in->first)
1038 port_region_marked_for_delete (in);
1039 input_free_completions (in);
1040 v = insert_char (in, key);
1042 else
1044 if (command != CK_Complete)
1045 input_free_completions (in);
1046 input_execute_cmd (in, command);
1047 v = MSG_HANDLED;
1048 if (in->first)
1049 input_update (in, TRUE); /* needed to clear in->first */
1052 input_update (in, TRUE);
1053 return v;
1056 /* --------------------------------------------------------------------------------------------- */
1058 /* This function is a test for a special input key used in complete.c */
1059 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1060 and 2 if it is a complete key */
1062 input_key_is_in_map (WInput * in, int key)
1064 unsigned long command;
1066 (void) in;
1068 command = keybind_lookup_keymap_command (input_map, key);
1069 if (command == CK_IgnoreKey)
1070 return 0;
1072 return (command == CK_Complete) ? 2 : 1;
1075 /* --------------------------------------------------------------------------------------------- */
1077 void
1078 input_assign_text (WInput * in, const char *text)
1080 input_free_completions (in);
1081 g_free (in->buffer);
1082 in->buffer = g_strdup (text); /* was in->buffer->text */
1083 in->current_max_size = strlen (in->buffer) + 1;
1084 in->point = str_length (in->buffer);
1085 in->mark = 0;
1086 in->need_push = TRUE;
1087 in->charpoint = 0;
1090 /* --------------------------------------------------------------------------------------------- */
1092 /* Inserts text in input line */
1093 void
1094 input_insert (WInput * in, const char *text, gboolean insert_extra_space)
1096 input_disable_update (in);
1097 while (*text != '\0')
1098 input_handle_char (in, (unsigned char) *text++); /* unsigned extension char->int */
1099 if (insert_extra_space)
1100 input_handle_char (in, ' ');
1101 input_enable_update (in);
1102 input_update (in, TRUE);
1105 /* --------------------------------------------------------------------------------------------- */
1107 void
1108 input_set_point (WInput * in, int pos)
1110 int max_pos;
1112 max_pos = str_length (in->buffer);
1113 pos = min (pos, max_pos);
1114 if (pos != in->point)
1115 input_free_completions (in);
1116 in->point = pos;
1117 in->charpoint = 0;
1118 input_update (in, TRUE);
1121 /* --------------------------------------------------------------------------------------------- */
1123 void
1124 input_update (WInput * in, gboolean clear_first)
1126 int has_history = 0;
1127 int i;
1128 int buf_len;
1129 const char *cp;
1130 int pw;
1132 if (should_show_history_button (in))
1133 has_history = HISTORY_BUTTON_WIDTH;
1135 if (in->disable_update != 0)
1136 return;
1138 buf_len = str_length (in->buffer);
1139 pw = str_term_width2 (in->buffer, in->point);
1141 /* Make the point visible */
1142 if ((pw < in->term_first_shown) || (pw >= in->term_first_shown + in->field_width - has_history))
1144 in->term_first_shown = pw - (in->field_width / 3);
1145 if (in->term_first_shown < 0)
1146 in->term_first_shown = 0;
1149 /* Adjust the mark */
1150 in->mark = min (in->mark, buf_len);
1152 if (has_history != 0)
1153 draw_history_button (in);
1155 if ((((Widget *) in)->options & W_DISABLED) != 0)
1156 tty_setcolor (DISABLED_COLOR);
1157 else if (in->first)
1158 tty_setcolor (in->color[WINPUTC_UNCHANGED]);
1159 else
1160 tty_setcolor (in->color[WINPUTC_MAIN]);
1162 widget_move (&in->widget, 0, 0);
1164 if (!in->is_password)
1166 if (!in->highlight)
1167 tty_print_string (str_term_substring (in->buffer, in->term_first_shown,
1168 in->field_width - has_history));
1169 else
1171 long m1, m2;
1173 if (input_eval_marks (in, &m1, &m2))
1175 tty_setcolor (in->color[WINPUTC_MAIN]);
1176 cp = str_term_substring (in->buffer, in->term_first_shown,
1177 in->field_width - has_history);
1178 tty_print_string (cp);
1179 tty_setcolor (in->color[WINPUTC_MARK]);
1180 if (m1 < in->term_first_shown)
1182 widget_move (&in->widget, 0, 0);
1183 tty_print_string (str_term_substring
1184 (in->buffer, in->term_first_shown,
1185 m2 - in->term_first_shown));
1187 else
1189 int sel_width;
1191 widget_move (&in->widget, 0, m1 - in->term_first_shown);
1192 sel_width =
1193 min (m2 - m1,
1194 (in->field_width - has_history) - (str_term_width2 (in->buffer, m1) -
1195 in->term_first_shown));
1196 tty_print_string (str_term_substring (in->buffer, m1, sel_width));
1201 else
1203 cp = str_term_substring (in->buffer, in->term_first_shown, in->field_width - has_history);
1204 for (i = 0; i < in->field_width - has_history; i++)
1206 if (i >= 0)
1208 tty_setcolor (in->color[WINPUTC_MAIN]);
1209 tty_print_char ((cp[0] != '\0') ? '*' : ' ');
1211 if (cp[0] != '\0')
1212 str_cnext_char (&cp);
1216 if (clear_first)
1217 in->first = FALSE;
1220 /* --------------------------------------------------------------------------------------------- */
1222 void
1223 input_enable_update (WInput * in)
1225 in->disable_update--;
1226 input_update (in, FALSE);
1229 /* --------------------------------------------------------------------------------------------- */
1231 void
1232 input_disable_update (WInput * in)
1234 in->disable_update++;
1237 /* --------------------------------------------------------------------------------------------- */
1239 /* Cleans the input line and adds the current text to the history */
1240 void
1241 input_clean (WInput * in)
1243 if (in->need_push)
1244 push_history (in, in->buffer);
1245 in->need_push = TRUE;
1246 in->buffer[0] = '\0';
1247 in->point = 0;
1248 in->charpoint = 0;
1249 in->mark = 0;
1250 in->highlight = FALSE;
1251 input_free_completions (in);
1252 input_update (in, FALSE);
1255 /* --------------------------------------------------------------------------------------------- */
1257 void
1258 input_free_completions (WInput * in)
1260 g_strfreev (in->completions);
1261 in->completions = NULL;
1264 /* --------------------------------------------------------------------------------------------- */