2 Widgets for the Midnight Commander
4 Copyright (C) 1994-2016
5 Free Software Foundation, Inc.
8 Radek Doulik, 1994, 1995
9 Miguel de Icaza, 1994, 1995
11 Andrej Borsenkow, 1996
13 Andrew Borodin <aborodin@vmail.ru>, 2009-2016
15 This file is part of the Midnight Commander.
17 The Midnight Commander is free software: you can redistribute it
18 and/or modify it under the terms of the GNU General Public License as
19 published by the Free Software Foundation, either version 3 of the License,
20 or (at your option) any later version.
22 The Midnight Commander is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with this program. If not, see <http://www.gnu.org/licenses/>.
32 * \brief Source: WInput widget
38 #include <sys/types.h>
41 #include "lib/global.h"
43 #include "lib/tty/tty.h"
44 #include "lib/tty/key.h" /* XCTRL and ALT macros */
45 #include "lib/fileloc.h"
47 #include "lib/strutil.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 gboolean quote
= FALSE
;
59 const global_keymap_t
*input_map
= NULL
;
61 /* Color styles for input widgets */
62 input_colors_t input_colors
;
64 /*** file scope macro definitions ****************************************************************/
66 #define LARGE_HISTORY_BUTTON 1
68 #ifdef LARGE_HISTORY_BUTTON
69 #define HISTORY_BUTTON_WIDTH 3
71 #define HISTORY_BUTTON_WIDTH 1
74 #define should_show_history_button(in) \
75 (in->history.list != NULL && WIDGET (in)->cols > HISTORY_BUTTON_WIDTH * 2 + 1 \
76 && WIDGET (in)->owner != NULL)
78 /*** file scope type declarations ****************************************************************/
80 /*** file scope variables ************************************************************************/
82 /* Input widgets have a global kill ring */
83 /* Pointer to killed data */
84 static char *kill_buffer
= NULL
;
86 /*** file scope functions ************************************************************************/
87 /* --------------------------------------------------------------------------------------------- */
90 get_history_length (const GList
* history
)
94 for (; history
!= NULL
; history
= (const GList
*) g_list_previous (history
))
100 /* --------------------------------------------------------------------------------------------- */
103 draw_history_button (WInput
* in
)
106 gboolean disabled
= (WIDGET (in
)->options
& W_DISABLED
) != 0;
108 if (g_list_next (in
->history
.current
) == NULL
)
110 else if (g_list_previous (in
->history
.current
) == NULL
)
115 widget_move (in
, 0, WIDGET (in
)->cols
- HISTORY_BUTTON_WIDTH
);
116 tty_setcolor (disabled
? DISABLED_COLOR
: in
->color
[WINPUTC_HISTORY
]);
118 #ifdef LARGE_HISTORY_BUTTON
119 tty_print_string ("[ ]");
120 widget_move (in
, 0, WIDGET (in
)->cols
- HISTORY_BUTTON_WIDTH
+ 1);
126 /* --------------------------------------------------------------------------------------------- */
129 input_mark_cmd (WInput
* in
, gboolean mark
)
131 in
->mark
= mark
? in
->point
: -1;
134 /* --------------------------------------------------------------------------------------------- */
137 input_eval_marks (WInput
* in
, long *start_mark
, long *end_mark
)
141 *start_mark
= MIN (in
->mark
, in
->point
);
142 *end_mark
= MAX (in
->mark
, in
->point
);
146 *start_mark
= *end_mark
= -1;
150 /* --------------------------------------------------------------------------------------------- */
153 delete_region (WInput
* in
, int x_first
, int x_last
)
155 int first
= MIN (x_first
, x_last
);
156 int last
= MAX (x_first
, x_last
);
159 input_mark_cmd (in
, FALSE
);
161 last
= str_offset_to_pos (in
->buffer
, last
);
162 first
= str_offset_to_pos (in
->buffer
, first
);
163 len
= strlen (&in
->buffer
[last
]) + 1;
164 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
166 in
->need_push
= TRUE
;
169 /* --------------------------------------------------------------------------------------------- */
172 do_show_hist (WInput
* in
)
177 len
= get_history_length (in
->history
.list
);
179 r
= history_show (&in
->history
.list
, WIDGET (in
),
180 g_list_position (in
->history
.list
, in
->history
.list
));
183 input_assign_text (in
, r
);
187 /* Has history cleaned up or not? */
188 if (len
!= get_history_length (in
->history
.list
))
189 in
->history
.changed
= TRUE
;
192 /* --------------------------------------------------------------------------------------------- */
194 * Strip password from incomplete url (just user:pass@host without VFS prefix).
196 * @param url partial URL
197 * @return newly allocated string without password
201 input_history_strip_password (char *url
)
203 char *at
, *delim
, *colon
;
205 at
= strrchr (url
, '@');
207 return g_strdup (url
);
209 /* TODO: handle ':' and '@' in password */
211 delim
= strstr (url
, VFS_PATH_URL_DELIMITER
);
213 colon
= strchr (delim
+ strlen (VFS_PATH_URL_DELIMITER
), ':');
215 colon
= strchr (url
, ':');
217 /* if 'colon' before 'at', 'colon' delimits user and password: user:password@host */
218 /* if 'colon' after 'at', 'colon' delimits host and port: user@host:port */
219 if (colon
!= NULL
&& colon
> at
)
223 return g_strdup (url
);
226 return g_strconcat (url
, at
, (char *) NULL
);
229 /* --------------------------------------------------------------------------------------------- */
232 push_history (WInput
* in
, const char *text
)
240 t
= g_strstrip (g_strdup (text
));
243 t
= g_strdup (empty
? "" : text
);
245 if (!empty
&& in
->history
.name
!= NULL
&& in
->strip_password
)
248 We got string user:pass@host without any VFS prefixes
249 and vfs_path_to_str_flags (t, VPF_STRIP_PASSWORD) doesn't work.
250 Therefore we want to strip password in separate algorithm
252 char *url_with_stripped_password
;
254 url_with_stripped_password
= input_history_strip_password (t
);
256 t
= url_with_stripped_password
;
259 if (in
->history
.list
== NULL
|| in
->history
.list
->data
== NULL
260 || strcmp (in
->history
.list
->data
, t
) != 0 || in
->history
.changed
)
262 in
->history
.list
= list_append_unique (in
->history
.list
, t
);
263 in
->history
.current
= in
->history
.list
;
264 in
->history
.changed
= TRUE
;
269 in
->need_push
= FALSE
;
272 /* --------------------------------------------------------------------------------------------- */
275 move_buffer_backward (WInput
* in
, int start
, int end
)
280 str_len
= str_length (in
->buffer
);
281 if (start
>= str_len
|| end
> str_len
+ 1)
284 pos
= str_offset_to_pos (in
->buffer
, start
);
285 len
= str_offset_to_pos (in
->buffer
, end
) - pos
;
287 for (i
= pos
; in
->buffer
[i
+ len
- 1]; i
++)
288 in
->buffer
[i
] = in
->buffer
[i
+ len
];
291 /* --------------------------------------------------------------------------------------------- */
294 insert_char (WInput
* in
, int c_code
)
299 if (input_eval_marks (in
, &m1
, &m2
))
300 delete_region (in
, m1
, m2
);
303 return MSG_NOT_HANDLED
;
305 if (in
->charpoint
>= MB_LEN_MAX
)
308 in
->charbuf
[in
->charpoint
] = c_code
;
311 res
= str_is_valid_char (in
->charbuf
, in
->charpoint
);
315 in
->charpoint
= 0; /* broken multibyte char, skip */
319 in
->need_push
= TRUE
;
320 if (strlen (in
->buffer
) + 1 + in
->charpoint
>= in
->current_max_size
)
322 /* Expand the buffer */
326 new_length
= in
->current_max_size
+ WIDGET (in
)->cols
+ in
->charpoint
;
327 narea
= g_try_renew (char, in
->buffer
, new_length
);
331 in
->current_max_size
= new_length
;
335 if (strlen (in
->buffer
) + in
->charpoint
< in
->current_max_size
)
338 /* bytes from begin */
339 size_t ins_point
= str_offset_to_pos (in
->buffer
, in
->point
);
341 size_t rest_bytes
= strlen (in
->buffer
+ ins_point
);
343 for (i
= rest_bytes
+ 1; i
> 0; i
--)
344 in
->buffer
[ins_point
+ i
+ in
->charpoint
- 1] = in
->buffer
[ins_point
+ i
- 1];
346 memcpy (in
->buffer
+ ins_point
, in
->charbuf
, in
->charpoint
);
354 /* --------------------------------------------------------------------------------------------- */
357 beginning_of_line (WInput
* in
)
363 /* --------------------------------------------------------------------------------------------- */
366 end_of_line (WInput
* in
)
368 in
->point
= str_length (in
->buffer
);
372 /* --------------------------------------------------------------------------------------------- */
375 backward_char (WInput
* in
)
379 act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
381 in
->point
-= str_cprev_noncomb_char (&act
, in
->buffer
);
385 /* --------------------------------------------------------------------------------------------- */
388 forward_char (WInput
* in
)
392 act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
394 in
->point
+= str_cnext_noncomb_char (&act
);
398 /* --------------------------------------------------------------------------------------------- */
401 forward_word (WInput
* in
)
405 p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
406 while (p
[0] != '\0' && (str_isspace (p
) || str_ispunct (p
)))
411 while (p
[0] != '\0' && !str_isspace (p
) && !str_ispunct (p
))
418 /* --------------------------------------------------------------------------------------------- */
421 backward_word (WInput
* in
)
425 p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
427 while (p
!= in
->buffer
)
433 if (!str_isspace (p
) && !str_ispunct (p
))
440 while (p
!= in
->buffer
)
443 if (str_isspace (p
) || str_ispunct (p
))
450 /* --------------------------------------------------------------------------------------------- */
453 backward_delete (WInput
* in
)
455 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
461 start
= in
->point
- str_cprev_noncomb_char (&act
, in
->buffer
);
462 move_buffer_backward (in
, start
, in
->point
);
464 in
->need_push
= TRUE
;
468 /* --------------------------------------------------------------------------------------------- */
471 delete_char (WInput
* in
)
476 act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
477 end
+= str_cnext_noncomb_char (&act
);
479 move_buffer_backward (in
, in
->point
, end
);
481 in
->need_push
= TRUE
;
484 /* --------------------------------------------------------------------------------------------- */
487 copy_region (WInput
* in
, int x_first
, int x_last
)
489 int first
= MIN (x_first
, x_last
);
490 int last
= MAX (x_first
, x_last
);
494 /* Copy selected files to clipboard */
495 mc_event_raise (MCEVENT_GROUP_FILEMANAGER
, "panel_save_current_file_to_clip_file", NULL
);
496 /* try use external clipboard utility */
497 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_file_to_ext_clip", NULL
);
501 g_free (kill_buffer
);
503 first
= str_offset_to_pos (in
->buffer
, first
);
504 last
= str_offset_to_pos (in
->buffer
, last
);
506 kill_buffer
= g_strndup (in
->buffer
+ first
, last
- first
);
508 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_text_to_file", kill_buffer
);
509 /* try use external clipboard utility */
510 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_file_to_ext_clip", NULL
);
513 /* --------------------------------------------------------------------------------------------- */
516 kill_word (WInput
* in
)
518 int old_point
= in
->point
;
522 new_point
= in
->point
;
523 in
->point
= old_point
;
525 delete_region (in
, old_point
, new_point
);
526 in
->need_push
= TRUE
;
530 /* --------------------------------------------------------------------------------------------- */
533 back_kill_word (WInput
* in
)
535 int old_point
= in
->point
;
539 new_point
= in
->point
;
540 in
->point
= old_point
;
542 delete_region (in
, old_point
, new_point
);
543 in
->need_push
= TRUE
;
546 /* --------------------------------------------------------------------------------------------- */
551 if (kill_buffer
!= NULL
)
556 for (p
= kill_buffer
; *p
!= '\0'; p
++)
557 insert_char (in
, *p
);
562 /* --------------------------------------------------------------------------------------------- */
565 kill_line (WInput
* in
)
569 chp
= str_offset_to_pos (in
->buffer
, in
->point
);
570 g_free (kill_buffer
);
571 kill_buffer
= g_strdup (&in
->buffer
[chp
]);
572 in
->buffer
[chp
] = '\0';
576 /* --------------------------------------------------------------------------------------------- */
579 clear_line (WInput
* in
)
581 in
->need_push
= TRUE
;
582 in
->buffer
[0] = '\0';
588 /* --------------------------------------------------------------------------------------------- */
591 ins_from_clip (WInput
* in
)
594 ev_clipboard_text_from_file_t event_data
;
596 /* try use external clipboard utility */
597 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_file_from_ext_clip", NULL
);
599 event_data
.text
= &p
;
600 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_text_from_file", &event_data
);
605 for (pp
= p
; *pp
!= '\0'; pp
++)
606 insert_char (in
, *pp
);
612 /* --------------------------------------------------------------------------------------------- */
615 hist_prev (WInput
* in
)
619 if (in
->history
.list
== NULL
)
623 push_history (in
, in
->buffer
);
625 prev
= g_list_previous (in
->history
.current
);
628 input_assign_text (in
, (char *) prev
->data
);
629 in
->history
.current
= prev
;
630 in
->history
.changed
= TRUE
;
631 in
->need_push
= FALSE
;
635 /* --------------------------------------------------------------------------------------------- */
638 hist_next (WInput
* in
)
644 push_history (in
, in
->buffer
);
645 input_assign_text (in
, "");
649 if (in
->history
.list
== NULL
)
652 next
= g_list_next (in
->history
.current
);
655 input_assign_text (in
, "");
656 in
->history
.current
= in
->history
.list
;
660 input_assign_text (in
, (char *) next
->data
);
661 in
->history
.current
= next
;
662 in
->history
.changed
= TRUE
;
663 in
->need_push
= FALSE
;
667 /* --------------------------------------------------------------------------------------------- */
670 port_region_marked_for_delete (WInput
* in
)
672 in
->buffer
[0] = '\0';
678 /* --------------------------------------------------------------------------------------------- */
681 input_execute_cmd (WInput
* in
, long command
)
683 cb_ret_t res
= MSG_HANDLED
;
689 case CK_MarkToWordBegin
:
690 case CK_MarkToWordEnd
:
693 /* a highlight command like shift-arrow */
696 input_mark_cmd (in
, FALSE
); /* clear */
697 input_mark_cmd (in
, TRUE
); /* marking on */
705 input_mark_cmd (in
, FALSE
);
715 beginning_of_line (in
);
726 case CK_MarkToWordBegin
:
734 case CK_MarkToWordEnd
:
741 if (input_eval_marks (in
, &m1
, &m2
))
742 delete_region (in
, m1
, m2
);
744 backward_delete (in
);
749 port_region_marked_for_delete (in
);
754 if (input_eval_marks (in
, &m1
, &m2
))
755 delete_region (in
, m1
, m2
);
760 case CK_DeleteToWordEnd
:
763 case CK_DeleteToWordBegin
:
767 input_mark_cmd (in
, TRUE
);
770 delete_region (in
, in
->point
, MAX (in
->mark
, 0));
779 copy_region (in
, MAX (in
->mark
, 0), in
->point
);
785 m
= MAX (in
->mark
, 0);
786 copy_region (in
, m
, in
->point
);
787 delete_region (in
, in
->point
, m
);
809 res
= MSG_NOT_HANDLED
;
816 case CK_MarkToWordBegin
:
817 case CK_MarkToWordEnd
:
830 /* --------------------------------------------------------------------------------------------- */
832 /* "history_load" event handler */
834 input_load_history (const gchar
* event_group_name
, const gchar
* event_name
,
835 gpointer init_data
, gpointer data
)
837 WInput
*in
= INPUT (init_data
);
838 ev_history_load_save_t
*ev
= (ev_history_load_save_t
*) data
;
840 (void) event_group_name
;
843 in
->history
.list
= history_load (ev
->cfg
, in
->history
.name
);
844 in
->history
.current
= in
->history
.list
;
846 if (in
->init_from_history
)
848 const char *def_text
= "";
850 if (in
->history
.list
!= NULL
&& in
->history
.list
->data
!= NULL
)
851 def_text
= (const char *) in
->history
.list
->data
;
853 input_assign_text (in
, def_text
);
859 /* --------------------------------------------------------------------------------------------- */
861 /* "history_save" event handler */
863 input_save_history (const gchar
* event_group_name
, const gchar
* event_name
,
864 gpointer init_data
, gpointer data
)
866 WInput
*in
= INPUT (init_data
);
868 (void) event_group_name
;
871 if (!in
->is_password
&& (WIDGET (in
)->owner
->ret_value
!= B_CANCEL
))
873 ev_history_load_save_t
*ev
= (ev_history_load_save_t
*) data
;
875 push_history (in
, in
->buffer
);
876 if (in
->history
.changed
)
877 history_save (ev
->cfg
, in
->history
.name
, in
->history
.list
);
878 in
->history
.changed
= FALSE
;
884 /* --------------------------------------------------------------------------------------------- */
887 input_destroy (WInput
* in
)
891 fprintf (stderr
, "Internal error: null Input *\n");
895 input_free_completions (in
);
898 if (in
->history
.list
!= NULL
)
900 /* history is already saved before this moment */
901 in
->history
.list
= g_list_first (in
->history
.list
);
902 g_list_free_full (in
->history
.list
, g_free
);
904 g_free (in
->history
.name
);
906 MC_PTR_FREE (kill_buffer
);
909 /* --------------------------------------------------------------------------------------------- */
912 * Calculates the buffer index (aka "point") corresponding to some screen coordinate.
915 input_screen_to_point (const WInput
* in
, int x
)
917 x
+= in
->term_first_shown
;
922 if (x
< str_term_width1 (in
->buffer
))
923 return str_column_to_pos (in
->buffer
, x
);
925 return str_length (in
->buffer
);
928 /* --------------------------------------------------------------------------------------------- */
931 input_mouse_callback (Widget
* w
, mouse_msg_t msg
, mouse_event_t
* event
)
933 /* save point between MSG_MOUSE_DOWN and MSG_MOUSE_DRAG */
934 static int prev_point
= 0;
935 WInput
*in
= INPUT (w
);
940 dlg_select_widget (w
);
943 if (event
->x
>= w
->cols
- HISTORY_BUTTON_WIDTH
&& should_show_history_button (in
))
947 input_mark_cmd (in
, FALSE
);
948 input_set_point (in
, input_screen_to_point (in
, event
->x
));
949 /* save point for the possible following MSG_MOUSE_DRAG action */
950 prev_point
= in
->point
;
955 /* start point: set marker using point before first MSG_MOUSE_DRAG action */
957 in
->mark
= prev_point
;
959 input_set_point (in
, input_screen_to_point (in
, event
->x
));
963 /* don't create highlight region of 0 length */
964 if (in
->mark
== in
->point
)
965 input_mark_cmd (in
, FALSE
);
970 /* --------------------------------------------------------------------------------------------- */
973 * Callback for applying new options to input widget.
976 * @param options options set
977 * @param enable TRUE if specified options should be added, FALSE if options should be removed
980 input_set_options_callback (Widget
* w
, widget_options_t options
, gboolean enable
)
982 WInput
*in
= INPUT (w
);
984 widget_default_set_options_callback (w
, options
, enable
);
985 if (in
->label
!= NULL
)
986 widget_set_options (WIDGET (in
->label
), options
, enable
);
989 /* --------------------------------------------------------------------------------------------- */
990 /*** public functions ****************************************************************************/
991 /* --------------------------------------------------------------------------------------------- */
993 /** Create new instance of WInput object.
994 * @param y Y coordinate
995 * @param x X coordinate
996 * @param input_colors Array of used colors
997 * @param width Widget width
998 * @param def_text Default text filled in widget
999 * @param histname Name of history
1000 * @param completion_flags Flags for specify type of completions
1001 * @return WInput object
1004 input_new (int y
, int x
, const int *colors
, int width
, const char *def_text
,
1005 const char *histname
, input_complete_t completion_flags
)
1010 in
= g_new (WInput
, 1);
1012 widget_init (w
, y
, x
, 1, width
, input_callback
, input_mouse_callback
);
1013 w
->options
|= W_IS_INPUT
;
1014 w
->set_options
= input_set_options_callback
;
1019 in
->term_first_shown
= 0;
1020 in
->disable_update
= 0;
1021 in
->is_password
= FALSE
;
1022 in
->strip_password
= FALSE
;
1024 /* in->buffer will be corrected in "history_load" event handler */
1025 in
->current_max_size
= width
+ 1;
1026 in
->buffer
= g_new0 (char, in
->current_max_size
);
1028 /* init completions before input_assign_text() call */
1029 in
->completions
= NULL
;
1030 in
->completion_flags
= completion_flags
;
1032 in
->init_from_history
= (def_text
== INPUT_LAST_TEXT
);
1034 if (in
->init_from_history
|| def_text
== NULL
)
1037 input_assign_text (in
, def_text
);
1039 /* prepare to history setup */
1040 in
->history
.list
= NULL
;
1041 in
->history
.current
= NULL
;
1042 in
->history
.changed
= FALSE
;
1043 in
->history
.name
= NULL
;
1044 if ((histname
!= NULL
) && (*histname
!= '\0'))
1045 in
->history
.name
= g_strdup (histname
);
1046 /* history will be loaded later */
1053 /* --------------------------------------------------------------------------------------------- */
1056 input_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
1058 WInput
*in
= INPUT (w
);
1064 /* subscribe to "history_load" event */
1065 mc_event_add (w
->owner
->event_group
, MCEVENT_HISTORY_LOAD
, input_load_history
, w
, NULL
);
1066 /* subscribe to "history_save" event */
1067 mc_event_add (w
->owner
->event_group
, MCEVENT_HISTORY_SAVE
, input_save_history
, w
, NULL
);
1071 if (parm
== XCTRL ('q'))
1074 v
= input_handle_char (in
, ascii_alpha_to_cntrl (tty_getch ()));
1079 /* Keys we want others to handle */
1080 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1081 || parm
== KEY_F (10) || parm
== '\n')
1082 return MSG_NOT_HANDLED
;
1084 /* When pasting multiline text, insert literal Enter */
1085 if ((parm
& ~KEY_M_MASK
) == '\n')
1088 v
= input_handle_char (in
, '\n');
1093 return input_handle_char (in
, parm
);
1096 return input_execute_cmd (in
, parm
);
1102 input_update (in
, FALSE
);
1106 widget_move (in
, 0, str_term_width2 (in
->buffer
, in
->point
) - in
->term_first_shown
);
1110 /* unsubscribe from "history_load" event */
1111 mc_event_del (w
->owner
->event_group
, MCEVENT_HISTORY_LOAD
, input_load_history
, w
);
1112 /* unsubscribe from "history_save" event */
1113 mc_event_del (w
->owner
->event_group
, MCEVENT_HISTORY_SAVE
, input_save_history
, w
);
1118 return widget_default_callback (w
, sender
, msg
, parm
, data
);
1122 /* --------------------------------------------------------------------------------------------- */
1125 input_set_default_colors (void)
1127 input_colors
[WINPUTC_MAIN
] = INPUT_COLOR
;
1128 input_colors
[WINPUTC_MARK
] = INPUT_MARK_COLOR
;
1129 input_colors
[WINPUTC_UNCHANGED
] = INPUT_UNCHANGED_COLOR
;
1130 input_colors
[WINPUTC_HISTORY
] = INPUT_HISTORY_COLOR
;
1133 /* --------------------------------------------------------------------------------------------- */
1136 input_handle_char (WInput
* in
, int key
)
1143 input_free_completions (in
);
1144 v
= insert_char (in
, key
);
1145 input_update (in
, TRUE
);
1150 command
= keybind_lookup_keymap_command (input_map
, key
);
1152 if (command
== CK_IgnoreKey
)
1155 return MSG_NOT_HANDLED
;
1157 port_region_marked_for_delete (in
);
1158 input_free_completions (in
);
1159 v
= insert_char (in
, key
);
1163 if (command
!= CK_Complete
)
1164 input_free_completions (in
);
1165 input_execute_cmd (in
, command
);
1168 input_update (in
, TRUE
); /* needed to clear in->first */
1171 input_update (in
, TRUE
);
1175 /* --------------------------------------------------------------------------------------------- */
1177 /* This function is a test for a special input key used in complete.c */
1178 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1179 and 2 if it is a complete key */
1181 input_key_is_in_map (WInput
* in
, int key
)
1187 command
= keybind_lookup_keymap_command (input_map
, key
);
1188 if (command
== CK_IgnoreKey
)
1191 return (command
== CK_Complete
) ? 2 : 1;
1194 /* --------------------------------------------------------------------------------------------- */
1197 input_assign_text (WInput
* in
, const char *text
)
1199 Widget
*w
= WIDGET (in
);
1200 size_t text_len
, buffer_len
;
1205 input_free_completions (in
);
1207 in
->need_push
= TRUE
;
1210 text_len
= strlen (text
);
1211 buffer_len
= 1 + MAX ((size_t) w
->cols
, text_len
);
1212 in
->current_max_size
= buffer_len
;
1213 if (buffer_len
> (size_t) w
->cols
)
1214 in
->buffer
= g_realloc (in
->buffer
, buffer_len
);
1215 memmove (in
->buffer
, text
, text_len
+ 1);
1216 in
->point
= str_length (in
->buffer
);
1217 input_update (in
, TRUE
);
1220 /* --------------------------------------------------------------------------------------------- */
1223 input_is_empty (const WInput
* in
)
1225 return (in
== NULL
|| in
->buffer
== NULL
|| in
->buffer
[0] == '\0');
1228 /* --------------------------------------------------------------------------------------------- */
1230 /* Inserts text in input line */
1232 input_insert (WInput
* in
, const char *text
, gboolean insert_extra_space
)
1234 input_disable_update (in
);
1235 while (*text
!= '\0')
1236 input_handle_char (in
, (unsigned char) *text
++); /* unsigned extension char->int */
1237 if (insert_extra_space
)
1238 input_handle_char (in
, ' ');
1239 input_enable_update (in
);
1240 input_update (in
, TRUE
);
1243 /* --------------------------------------------------------------------------------------------- */
1246 input_set_point (WInput
* in
, int pos
)
1250 max_pos
= str_length (in
->buffer
);
1251 pos
= MIN (pos
, max_pos
);
1252 if (pos
!= in
->point
)
1253 input_free_completions (in
);
1256 input_update (in
, TRUE
);
1259 /* --------------------------------------------------------------------------------------------- */
1262 input_update (WInput
* in
, gboolean clear_first
)
1264 Widget
*w
= WIDGET (in
);
1265 int has_history
= 0;
1270 if (in
->disable_update
!= 0)
1273 /* don't draw widget not put into dialog */
1274 if (w
->owner
== NULL
|| w
->owner
->state
!= DLG_ACTIVE
)
1277 if (should_show_history_button (in
))
1278 has_history
= HISTORY_BUTTON_WIDTH
;
1280 buf_len
= str_length (in
->buffer
);
1282 /* Adjust the mark */
1283 in
->mark
= MIN (in
->mark
, buf_len
);
1285 pw
= str_term_width2 (in
->buffer
, in
->point
);
1287 /* Make the point visible */
1288 if ((pw
< in
->term_first_shown
) || (pw
>= in
->term_first_shown
+ w
->cols
- has_history
))
1290 in
->term_first_shown
= pw
- (w
->cols
/ 3);
1291 if (in
->term_first_shown
< 0)
1292 in
->term_first_shown
= 0;
1295 if (has_history
!= 0)
1296 draw_history_button (in
);
1298 if ((w
->options
& W_DISABLED
) != 0)
1299 tty_setcolor (DISABLED_COLOR
);
1301 tty_setcolor (in
->color
[WINPUTC_UNCHANGED
]);
1303 tty_setcolor (in
->color
[WINPUTC_MAIN
]);
1305 widget_move (in
, 0, 0);
1307 if (!in
->is_password
)
1310 tty_print_string (str_term_substring (in
->buffer
, in
->term_first_shown
,
1311 w
->cols
- has_history
));
1316 if (input_eval_marks (in
, &m1
, &m2
))
1318 tty_setcolor (in
->color
[WINPUTC_MAIN
]);
1319 cp
= str_term_substring (in
->buffer
, in
->term_first_shown
, w
->cols
- has_history
);
1320 tty_print_string (cp
);
1321 tty_setcolor (in
->color
[WINPUTC_MARK
]);
1322 if (m1
< in
->term_first_shown
)
1324 widget_move (in
, 0, 0);
1325 tty_print_string (str_term_substring
1326 (in
->buffer
, in
->term_first_shown
,
1327 m2
- in
->term_first_shown
));
1331 int sel_width
, buf_width
;
1333 widget_move (in
, 0, m1
- in
->term_first_shown
);
1334 buf_width
= str_term_width2 (in
->buffer
, m1
);
1336 MIN (m2
- m1
, (w
->cols
- has_history
) - (buf_width
- in
->term_first_shown
));
1337 tty_print_string (str_term_substring (in
->buffer
, m1
, sel_width
));
1346 cp
= str_term_substring (in
->buffer
, in
->term_first_shown
, w
->cols
- has_history
);
1347 tty_setcolor (in
->color
[WINPUTC_MAIN
]);
1348 for (i
= 0; i
< w
->cols
- has_history
; i
++)
1350 if (i
< (buf_len
- in
->term_first_shown
) && cp
[0] != '\0')
1351 tty_print_char ('*');
1353 tty_print_char (' ');
1355 str_cnext_char (&cp
);
1363 /* --------------------------------------------------------------------------------------------- */
1366 input_enable_update (WInput
* in
)
1368 in
->disable_update
--;
1369 input_update (in
, FALSE
);
1372 /* --------------------------------------------------------------------------------------------- */
1375 input_disable_update (WInput
* in
)
1377 in
->disable_update
++;
1380 /* --------------------------------------------------------------------------------------------- */
1383 * Cleans the input line and adds the current text to the history
1385 * @param in the input line
1388 input_clean (WInput
* in
)
1390 push_history (in
, in
->buffer
);
1391 in
->need_push
= TRUE
;
1392 in
->buffer
[0] = '\0';
1396 input_free_completions (in
);
1397 input_update (in
, FALSE
);
1400 /* --------------------------------------------------------------------------------------------- */
1403 input_free_completions (WInput
* in
)
1405 g_strfreev (in
->completions
);
1406 in
->completions
= NULL
;
1409 /* --------------------------------------------------------------------------------------------- */