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
)
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 disabled
= widget_get_state (WIDGET (in
), WST_DISABLED
);
117 tty_setcolor (disabled
? DISABLED_COLOR
: in
->color
[WINPUTC_HISTORY
]);
119 #ifdef LARGE_HISTORY_BUTTON
120 tty_print_string ("[ ]");
121 widget_move (in
, 0, WIDGET (in
)->cols
- HISTORY_BUTTON_WIDTH
+ 1);
127 /* --------------------------------------------------------------------------------------------- */
130 input_mark_cmd (WInput
* in
, gboolean mark
)
132 in
->mark
= mark
? in
->point
: -1;
135 /* --------------------------------------------------------------------------------------------- */
138 input_eval_marks (WInput
* in
, long *start_mark
, long *end_mark
)
142 *start_mark
= MIN (in
->mark
, in
->point
);
143 *end_mark
= MAX (in
->mark
, in
->point
);
147 *start_mark
= *end_mark
= -1;
151 /* --------------------------------------------------------------------------------------------- */
154 delete_region (WInput
* in
, int x_first
, int x_last
)
156 int first
= MIN (x_first
, x_last
);
157 int last
= MAX (x_first
, x_last
);
160 input_mark_cmd (in
, FALSE
);
162 last
= str_offset_to_pos (in
->buffer
, last
);
163 first
= str_offset_to_pos (in
->buffer
, first
);
164 len
= strlen (&in
->buffer
[last
]) + 1;
165 memmove (&in
->buffer
[first
], &in
->buffer
[last
], len
);
167 in
->need_push
= TRUE
;
170 /* --------------------------------------------------------------------------------------------- */
173 do_show_hist (WInput
* in
)
178 len
= get_history_length (in
->history
.list
);
180 r
= history_show (&in
->history
.list
, WIDGET (in
),
181 g_list_position (in
->history
.list
, in
->history
.list
));
184 input_assign_text (in
, r
);
188 /* Has history cleaned up or not? */
189 if (len
!= get_history_length (in
->history
.list
))
190 in
->history
.changed
= TRUE
;
193 /* --------------------------------------------------------------------------------------------- */
195 * Strip password from incomplete url (just user:pass@host without VFS prefix).
197 * @param url partial URL
198 * @return newly allocated string without password
202 input_history_strip_password (char *url
)
204 char *at
, *delim
, *colon
;
206 at
= strrchr (url
, '@');
208 return g_strdup (url
);
210 /* TODO: handle ':' and '@' in password */
212 delim
= strstr (url
, VFS_PATH_URL_DELIMITER
);
214 colon
= strchr (delim
+ strlen (VFS_PATH_URL_DELIMITER
), ':');
216 colon
= strchr (url
, ':');
218 /* if 'colon' before 'at', 'colon' delimits user and password: user:password@host */
219 /* if 'colon' after 'at', 'colon' delimits host and port: user@host:port */
220 if (colon
!= NULL
&& colon
> at
)
224 return g_strdup (url
);
227 return g_strconcat (url
, at
, (char *) NULL
);
230 /* --------------------------------------------------------------------------------------------- */
233 push_history (WInput
* in
, const char *text
)
241 t
= g_strstrip (g_strdup (text
));
244 t
= g_strdup (empty
? "" : text
);
246 if (!empty
&& in
->history
.name
!= NULL
&& in
->strip_password
)
249 We got string user:pass@host without any VFS prefixes
250 and vfs_path_to_str_flags (t, VPF_STRIP_PASSWORD) doesn't work.
251 Therefore we want to strip password in separate algorithm
253 char *url_with_stripped_password
;
255 url_with_stripped_password
= input_history_strip_password (t
);
257 t
= url_with_stripped_password
;
260 if (in
->history
.list
== NULL
|| in
->history
.list
->data
== NULL
261 || strcmp (in
->history
.list
->data
, t
) != 0 || in
->history
.changed
)
263 in
->history
.list
= list_append_unique (in
->history
.list
, t
);
264 in
->history
.current
= in
->history
.list
;
265 in
->history
.changed
= TRUE
;
270 in
->need_push
= FALSE
;
273 /* --------------------------------------------------------------------------------------------- */
276 move_buffer_backward (WInput
* in
, int start
, int end
)
281 str_len
= str_length (in
->buffer
);
282 if (start
>= str_len
|| end
> str_len
+ 1)
285 pos
= str_offset_to_pos (in
->buffer
, start
);
286 len
= str_offset_to_pos (in
->buffer
, end
) - pos
;
288 for (i
= pos
; in
->buffer
[i
+ len
- 1]; i
++)
289 in
->buffer
[i
] = in
->buffer
[i
+ len
];
292 /* --------------------------------------------------------------------------------------------- */
295 insert_char (WInput
* in
, int c_code
)
300 if (input_eval_marks (in
, &m1
, &m2
))
301 delete_region (in
, m1
, m2
);
304 return MSG_NOT_HANDLED
;
306 if (in
->charpoint
>= MB_LEN_MAX
)
309 in
->charbuf
[in
->charpoint
] = c_code
;
312 res
= str_is_valid_char (in
->charbuf
, in
->charpoint
);
316 in
->charpoint
= 0; /* broken multibyte char, skip */
320 in
->need_push
= TRUE
;
321 if (strlen (in
->buffer
) + 1 + in
->charpoint
>= in
->current_max_size
)
323 /* Expand the buffer */
327 new_length
= in
->current_max_size
+ WIDGET (in
)->cols
+ in
->charpoint
;
328 narea
= g_try_renew (char, in
->buffer
, new_length
);
332 in
->current_max_size
= new_length
;
336 if (strlen (in
->buffer
) + in
->charpoint
< in
->current_max_size
)
339 /* bytes from begin */
340 size_t ins_point
= str_offset_to_pos (in
->buffer
, in
->point
);
342 size_t rest_bytes
= strlen (in
->buffer
+ ins_point
);
344 for (i
= rest_bytes
+ 1; i
> 0; i
--)
345 in
->buffer
[ins_point
+ i
+ in
->charpoint
- 1] = in
->buffer
[ins_point
+ i
- 1];
347 memcpy (in
->buffer
+ ins_point
, in
->charbuf
, in
->charpoint
);
355 /* --------------------------------------------------------------------------------------------- */
358 beginning_of_line (WInput
* in
)
364 /* --------------------------------------------------------------------------------------------- */
367 end_of_line (WInput
* in
)
369 in
->point
= str_length (in
->buffer
);
373 /* --------------------------------------------------------------------------------------------- */
376 backward_char (WInput
* in
)
380 act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
382 in
->point
-= str_cprev_noncomb_char (&act
, in
->buffer
);
386 /* --------------------------------------------------------------------------------------------- */
389 forward_char (WInput
* in
)
393 act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
395 in
->point
+= str_cnext_noncomb_char (&act
);
399 /* --------------------------------------------------------------------------------------------- */
402 forward_word (WInput
* in
)
406 p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
407 while (p
[0] != '\0' && (str_isspace (p
) || str_ispunct (p
)))
412 while (p
[0] != '\0' && !str_isspace (p
) && !str_ispunct (p
))
419 /* --------------------------------------------------------------------------------------------- */
422 backward_word (WInput
* in
)
426 p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
428 while (p
!= in
->buffer
)
434 if (!str_isspace (p
) && !str_ispunct (p
))
441 while (p
!= in
->buffer
)
444 if (str_isspace (p
) || str_ispunct (p
))
451 /* --------------------------------------------------------------------------------------------- */
454 backward_delete (WInput
* in
)
456 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
462 start
= in
->point
- str_cprev_noncomb_char (&act
, in
->buffer
);
463 move_buffer_backward (in
, start
, in
->point
);
465 in
->need_push
= TRUE
;
469 /* --------------------------------------------------------------------------------------------- */
472 delete_char (WInput
* in
)
477 act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
478 end
+= str_cnext_noncomb_char (&act
);
480 move_buffer_backward (in
, in
->point
, end
);
482 in
->need_push
= TRUE
;
485 /* --------------------------------------------------------------------------------------------- */
488 copy_region (WInput
* in
, int x_first
, int x_last
)
490 int first
= MIN (x_first
, x_last
);
491 int last
= MAX (x_first
, x_last
);
495 /* Copy selected files to clipboard */
496 mc_event_raise (MCEVENT_GROUP_FILEMANAGER
, "panel_save_current_file_to_clip_file", NULL
);
497 /* try use external clipboard utility */
498 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_file_to_ext_clip", NULL
);
502 g_free (kill_buffer
);
504 first
= str_offset_to_pos (in
->buffer
, first
);
505 last
= str_offset_to_pos (in
->buffer
, last
);
507 kill_buffer
= g_strndup (in
->buffer
+ first
, last
- first
);
509 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_text_to_file", kill_buffer
);
510 /* try use external clipboard utility */
511 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_file_to_ext_clip", NULL
);
514 /* --------------------------------------------------------------------------------------------- */
517 kill_word (WInput
* in
)
519 int old_point
= in
->point
;
523 new_point
= in
->point
;
524 in
->point
= old_point
;
526 delete_region (in
, old_point
, new_point
);
527 in
->need_push
= TRUE
;
531 /* --------------------------------------------------------------------------------------------- */
534 back_kill_word (WInput
* in
)
536 int old_point
= in
->point
;
540 new_point
= in
->point
;
541 in
->point
= old_point
;
543 delete_region (in
, old_point
, new_point
);
544 in
->need_push
= TRUE
;
547 /* --------------------------------------------------------------------------------------------- */
552 if (kill_buffer
!= NULL
)
557 for (p
= kill_buffer
; *p
!= '\0'; p
++)
558 insert_char (in
, *p
);
563 /* --------------------------------------------------------------------------------------------- */
566 kill_line (WInput
* in
)
570 chp
= str_offset_to_pos (in
->buffer
, in
->point
);
571 g_free (kill_buffer
);
572 kill_buffer
= g_strdup (&in
->buffer
[chp
]);
573 in
->buffer
[chp
] = '\0';
577 /* --------------------------------------------------------------------------------------------- */
580 clear_line (WInput
* in
)
582 in
->need_push
= TRUE
;
583 in
->buffer
[0] = '\0';
589 /* --------------------------------------------------------------------------------------------- */
592 ins_from_clip (WInput
* in
)
595 ev_clipboard_text_from_file_t event_data
;
597 /* try use external clipboard utility */
598 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_file_from_ext_clip", NULL
);
600 event_data
.text
= &p
;
601 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_text_from_file", &event_data
);
606 for (pp
= p
; *pp
!= '\0'; pp
++)
607 insert_char (in
, *pp
);
613 /* --------------------------------------------------------------------------------------------- */
616 hist_prev (WInput
* in
)
620 if (in
->history
.list
== NULL
)
624 push_history (in
, in
->buffer
);
626 prev
= g_list_previous (in
->history
.current
);
629 input_assign_text (in
, (char *) prev
->data
);
630 in
->history
.current
= prev
;
631 in
->history
.changed
= TRUE
;
632 in
->need_push
= FALSE
;
636 /* --------------------------------------------------------------------------------------------- */
639 hist_next (WInput
* in
)
645 push_history (in
, in
->buffer
);
646 input_assign_text (in
, "");
650 if (in
->history
.list
== NULL
)
653 next
= g_list_next (in
->history
.current
);
656 input_assign_text (in
, "");
657 in
->history
.current
= in
->history
.list
;
661 input_assign_text (in
, (char *) next
->data
);
662 in
->history
.current
= next
;
663 in
->history
.changed
= TRUE
;
664 in
->need_push
= FALSE
;
668 /* --------------------------------------------------------------------------------------------- */
671 port_region_marked_for_delete (WInput
* in
)
673 in
->buffer
[0] = '\0';
679 /* --------------------------------------------------------------------------------------------- */
682 input_execute_cmd (WInput
* in
, long command
)
684 cb_ret_t res
= MSG_HANDLED
;
690 case CK_MarkToWordBegin
:
691 case CK_MarkToWordEnd
:
694 /* a highlight command like shift-arrow */
697 input_mark_cmd (in
, FALSE
); /* clear */
698 input_mark_cmd (in
, TRUE
); /* marking on */
706 input_mark_cmd (in
, FALSE
);
716 beginning_of_line (in
);
727 case CK_MarkToWordBegin
:
735 case CK_MarkToWordEnd
:
742 if (input_eval_marks (in
, &m1
, &m2
))
743 delete_region (in
, m1
, m2
);
745 backward_delete (in
);
750 port_region_marked_for_delete (in
);
755 if (input_eval_marks (in
, &m1
, &m2
))
756 delete_region (in
, m1
, m2
);
761 case CK_DeleteToWordEnd
:
764 case CK_DeleteToWordBegin
:
768 input_mark_cmd (in
, TRUE
);
771 delete_region (in
, in
->point
, MAX (in
->mark
, 0));
780 copy_region (in
, MAX (in
->mark
, 0), in
->point
);
786 m
= MAX (in
->mark
, 0);
787 copy_region (in
, m
, in
->point
);
788 delete_region (in
, in
->point
, m
);
810 res
= MSG_NOT_HANDLED
;
817 case CK_MarkToWordBegin
:
818 case CK_MarkToWordEnd
:
831 /* --------------------------------------------------------------------------------------------- */
833 /* "history_load" event handler */
835 input_load_history (const gchar
* event_group_name
, const gchar
* event_name
,
836 gpointer init_data
, gpointer data
)
838 WInput
*in
= INPUT (init_data
);
839 ev_history_load_save_t
*ev
= (ev_history_load_save_t
*) data
;
841 (void) event_group_name
;
844 in
->history
.list
= history_load (ev
->cfg
, in
->history
.name
);
845 in
->history
.current
= in
->history
.list
;
847 if (in
->init_from_history
)
849 const char *def_text
= "";
851 if (in
->history
.list
!= NULL
&& in
->history
.list
->data
!= NULL
)
852 def_text
= (const char *) in
->history
.list
->data
;
854 input_assign_text (in
, def_text
);
860 /* --------------------------------------------------------------------------------------------- */
862 /* "history_save" event handler */
864 input_save_history (const gchar
* event_group_name
, const gchar
* event_name
,
865 gpointer init_data
, gpointer data
)
867 WInput
*in
= INPUT (init_data
);
869 (void) event_group_name
;
872 if (!in
->is_password
&& (WIDGET (in
)->owner
->ret_value
!= B_CANCEL
))
874 ev_history_load_save_t
*ev
= (ev_history_load_save_t
*) data
;
876 push_history (in
, in
->buffer
);
877 if (in
->history
.changed
)
878 history_save (ev
->cfg
, in
->history
.name
, in
->history
.list
);
879 in
->history
.changed
= FALSE
;
885 /* --------------------------------------------------------------------------------------------- */
888 input_destroy (WInput
* in
)
892 fprintf (stderr
, "Internal error: null Input *\n");
896 input_free_completions (in
);
899 if (in
->history
.list
!= NULL
)
901 /* history is already saved before this moment */
902 in
->history
.list
= g_list_first (in
->history
.list
);
903 g_list_free_full (in
->history
.list
, g_free
);
905 g_free (in
->history
.name
);
907 MC_PTR_FREE (kill_buffer
);
910 /* --------------------------------------------------------------------------------------------- */
913 * Calculates the buffer index (aka "point") corresponding to some screen coordinate.
916 input_screen_to_point (const WInput
* in
, int x
)
918 x
+= in
->term_first_shown
;
923 if (x
< str_term_width1 (in
->buffer
))
924 return str_column_to_pos (in
->buffer
, x
);
926 return str_length (in
->buffer
);
929 /* --------------------------------------------------------------------------------------------- */
932 input_mouse_callback (Widget
* w
, mouse_msg_t msg
, mouse_event_t
* event
)
934 /* save point between MSG_MOUSE_DOWN and MSG_MOUSE_DRAG */
935 static int prev_point
= 0;
936 WInput
*in
= INPUT (w
);
944 if (event
->x
>= w
->cols
- HISTORY_BUTTON_WIDTH
&& should_show_history_button (in
))
948 input_mark_cmd (in
, FALSE
);
949 input_set_point (in
, input_screen_to_point (in
, event
->x
));
950 /* save point for the possible following MSG_MOUSE_DRAG action */
951 prev_point
= in
->point
;
956 /* start point: set marker using point before first MSG_MOUSE_DRAG action */
958 in
->mark
= prev_point
;
960 input_set_point (in
, input_screen_to_point (in
, event
->x
));
964 /* don't create highlight region of 0 length */
965 if (in
->mark
== in
->point
)
966 input_mark_cmd (in
, FALSE
);
971 /* --------------------------------------------------------------------------------------------- */
972 /*** public functions ****************************************************************************/
973 /* --------------------------------------------------------------------------------------------- */
975 /** Create new instance of WInput object.
976 * @param y Y coordinate
977 * @param x X coordinate
978 * @param input_colors Array of used colors
979 * @param width Widget width
980 * @param def_text Default text filled in widget
981 * @param histname Name of history
982 * @param completion_flags Flags for specify type of completions
983 * @return WInput object
986 input_new (int y
, int x
, const int *colors
, int width
, const char *def_text
,
987 const char *histname
, input_complete_t completion_flags
)
992 in
= g_new (WInput
, 1);
994 widget_init (w
, y
, x
, 1, width
, input_callback
, input_mouse_callback
);
995 w
->options
|= WOP_SELECTABLE
| WOP_IS_INPUT
| WOP_WANT_CURSOR
;
1000 in
->term_first_shown
= 0;
1001 in
->disable_update
= 0;
1002 in
->is_password
= FALSE
;
1003 in
->strip_password
= FALSE
;
1005 /* in->buffer will be corrected in "history_load" event handler */
1006 in
->current_max_size
= width
+ 1;
1007 in
->buffer
= g_new0 (char, in
->current_max_size
);
1009 /* init completions before input_assign_text() call */
1010 in
->completions
= NULL
;
1011 in
->completion_flags
= completion_flags
;
1013 in
->init_from_history
= (def_text
== INPUT_LAST_TEXT
);
1015 if (in
->init_from_history
|| def_text
== NULL
)
1018 input_assign_text (in
, def_text
);
1020 /* prepare to history setup */
1021 in
->history
.list
= NULL
;
1022 in
->history
.current
= NULL
;
1023 in
->history
.changed
= FALSE
;
1024 in
->history
.name
= NULL
;
1025 if ((histname
!= NULL
) && (*histname
!= '\0'))
1026 in
->history
.name
= g_strdup (histname
);
1027 /* history will be loaded later */
1034 /* --------------------------------------------------------------------------------------------- */
1037 input_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
1039 WInput
*in
= INPUT (w
);
1045 /* subscribe to "history_load" event */
1046 mc_event_add (w
->owner
->event_group
, MCEVENT_HISTORY_LOAD
, input_load_history
, w
, NULL
);
1047 /* subscribe to "history_save" event */
1048 mc_event_add (w
->owner
->event_group
, MCEVENT_HISTORY_SAVE
, input_save_history
, w
, NULL
);
1049 if (in
->label
!= NULL
)
1050 widget_set_state (WIDGET (in
->label
), WST_DISABLED
, widget_get_state (w
, WST_DISABLED
));
1054 if (parm
== XCTRL ('q'))
1057 v
= input_handle_char (in
, ascii_alpha_to_cntrl (tty_getch ()));
1062 /* Keys we want others to handle */
1063 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1064 || parm
== KEY_F (10) || parm
== '\n')
1065 return MSG_NOT_HANDLED
;
1067 /* When pasting multiline text, insert literal Enter */
1068 if ((parm
& ~KEY_M_MASK
) == '\n')
1071 v
= input_handle_char (in
, '\n');
1076 return input_handle_char (in
, parm
);
1079 return input_execute_cmd (in
, parm
);
1082 input_update (in
, FALSE
);
1087 if (in
->label
!= NULL
)
1088 widget_set_state (WIDGET (in
->label
), WST_DISABLED
, msg
== MSG_DISABLE
);
1092 widget_move (in
, 0, str_term_width2 (in
->buffer
, in
->point
) - in
->term_first_shown
);
1096 /* unsubscribe from "history_load" event */
1097 mc_event_del (w
->owner
->event_group
, MCEVENT_HISTORY_LOAD
, input_load_history
, w
);
1098 /* unsubscribe from "history_save" event */
1099 mc_event_del (w
->owner
->event_group
, MCEVENT_HISTORY_SAVE
, input_save_history
, w
);
1104 return widget_default_callback (w
, sender
, msg
, parm
, data
);
1108 /* --------------------------------------------------------------------------------------------- */
1111 input_set_default_colors (void)
1113 input_colors
[WINPUTC_MAIN
] = INPUT_COLOR
;
1114 input_colors
[WINPUTC_MARK
] = INPUT_MARK_COLOR
;
1115 input_colors
[WINPUTC_UNCHANGED
] = INPUT_UNCHANGED_COLOR
;
1116 input_colors
[WINPUTC_HISTORY
] = INPUT_HISTORY_COLOR
;
1119 /* --------------------------------------------------------------------------------------------- */
1122 input_handle_char (WInput
* in
, int key
)
1129 input_free_completions (in
);
1130 v
= insert_char (in
, key
);
1131 input_update (in
, TRUE
);
1136 command
= keybind_lookup_keymap_command (input_map
, key
);
1138 if (command
== CK_IgnoreKey
)
1141 return MSG_NOT_HANDLED
;
1143 port_region_marked_for_delete (in
);
1144 input_free_completions (in
);
1145 v
= insert_char (in
, key
);
1149 if (command
!= CK_Complete
)
1150 input_free_completions (in
);
1151 input_execute_cmd (in
, command
);
1154 input_update (in
, TRUE
); /* needed to clear in->first */
1157 input_update (in
, TRUE
);
1161 /* --------------------------------------------------------------------------------------------- */
1163 /* This function is a test for a special input key used in complete.c */
1164 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1165 and 2 if it is a complete key */
1167 input_key_is_in_map (WInput
* in
, int key
)
1173 command
= keybind_lookup_keymap_command (input_map
, key
);
1174 if (command
== CK_IgnoreKey
)
1177 return (command
== CK_Complete
) ? 2 : 1;
1180 /* --------------------------------------------------------------------------------------------- */
1183 input_assign_text (WInput
* in
, const char *text
)
1185 Widget
*w
= WIDGET (in
);
1186 size_t text_len
, buffer_len
;
1191 input_free_completions (in
);
1193 in
->need_push
= TRUE
;
1196 text_len
= strlen (text
);
1197 buffer_len
= 1 + MAX ((size_t) w
->cols
, text_len
);
1198 in
->current_max_size
= buffer_len
;
1199 if (buffer_len
> (size_t) w
->cols
)
1200 in
->buffer
= g_realloc (in
->buffer
, buffer_len
);
1201 memmove (in
->buffer
, text
, text_len
+ 1);
1202 in
->point
= str_length (in
->buffer
);
1203 input_update (in
, TRUE
);
1206 /* --------------------------------------------------------------------------------------------- */
1209 input_is_empty (const WInput
* in
)
1211 return (in
== NULL
|| in
->buffer
== NULL
|| in
->buffer
[0] == '\0');
1214 /* --------------------------------------------------------------------------------------------- */
1216 /* Inserts text in input line */
1218 input_insert (WInput
* in
, const char *text
, gboolean insert_extra_space
)
1220 input_disable_update (in
);
1221 while (*text
!= '\0')
1222 input_handle_char (in
, (unsigned char) *text
++); /* unsigned extension char->int */
1223 if (insert_extra_space
)
1224 input_handle_char (in
, ' ');
1225 input_enable_update (in
);
1226 input_update (in
, TRUE
);
1229 /* --------------------------------------------------------------------------------------------- */
1232 input_set_point (WInput
* in
, int pos
)
1236 max_pos
= str_length (in
->buffer
);
1237 pos
= MIN (pos
, max_pos
);
1238 if (pos
!= in
->point
)
1239 input_free_completions (in
);
1242 input_update (in
, TRUE
);
1245 /* --------------------------------------------------------------------------------------------- */
1248 input_update (WInput
* in
, gboolean clear_first
)
1250 Widget
*w
= WIDGET (in
);
1251 int has_history
= 0;
1256 if (in
->disable_update
!= 0)
1259 /* don't draw widget not put into dialog */
1260 if (w
->owner
== NULL
|| !widget_get_state (WIDGET (w
->owner
), WST_ACTIVE
))
1263 if (should_show_history_button (in
))
1264 has_history
= HISTORY_BUTTON_WIDTH
;
1266 buf_len
= str_length (in
->buffer
);
1268 /* Adjust the mark */
1269 in
->mark
= MIN (in
->mark
, buf_len
);
1271 pw
= str_term_width2 (in
->buffer
, in
->point
);
1273 /* Make the point visible */
1274 if ((pw
< in
->term_first_shown
) || (pw
>= in
->term_first_shown
+ w
->cols
- has_history
))
1276 in
->term_first_shown
= pw
- (w
->cols
/ 3);
1277 if (in
->term_first_shown
< 0)
1278 in
->term_first_shown
= 0;
1281 if (has_history
!= 0)
1282 draw_history_button (in
);
1284 if (widget_get_state (w
, WST_DISABLED
))
1285 tty_setcolor (DISABLED_COLOR
);
1287 tty_setcolor (in
->color
[WINPUTC_UNCHANGED
]);
1289 tty_setcolor (in
->color
[WINPUTC_MAIN
]);
1291 widget_move (in
, 0, 0);
1293 if (!in
->is_password
)
1296 tty_print_string (str_term_substring (in
->buffer
, in
->term_first_shown
,
1297 w
->cols
- has_history
));
1302 if (input_eval_marks (in
, &m1
, &m2
))
1304 tty_setcolor (in
->color
[WINPUTC_MAIN
]);
1305 cp
= str_term_substring (in
->buffer
, in
->term_first_shown
, w
->cols
- has_history
);
1306 tty_print_string (cp
);
1307 tty_setcolor (in
->color
[WINPUTC_MARK
]);
1308 if (m1
< in
->term_first_shown
)
1310 widget_move (in
, 0, 0);
1311 tty_print_string (str_term_substring
1312 (in
->buffer
, in
->term_first_shown
,
1313 m2
- in
->term_first_shown
));
1317 int sel_width
, buf_width
;
1319 widget_move (in
, 0, m1
- in
->term_first_shown
);
1320 buf_width
= str_term_width2 (in
->buffer
, m1
);
1322 MIN (m2
- m1
, (w
->cols
- has_history
) - (buf_width
- in
->term_first_shown
));
1323 tty_print_string (str_term_substring (in
->buffer
, m1
, sel_width
));
1332 cp
= str_term_substring (in
->buffer
, in
->term_first_shown
, w
->cols
- has_history
);
1333 tty_setcolor (in
->color
[WINPUTC_MAIN
]);
1334 for (i
= 0; i
< w
->cols
- has_history
; i
++)
1336 if (i
< (buf_len
- in
->term_first_shown
) && cp
[0] != '\0')
1337 tty_print_char ('*');
1339 tty_print_char (' ');
1341 str_cnext_char (&cp
);
1349 /* --------------------------------------------------------------------------------------------- */
1352 input_enable_update (WInput
* in
)
1354 in
->disable_update
--;
1355 input_update (in
, FALSE
);
1358 /* --------------------------------------------------------------------------------------------- */
1361 input_disable_update (WInput
* in
)
1363 in
->disable_update
++;
1366 /* --------------------------------------------------------------------------------------------- */
1369 * Cleans the input line and adds the current text to the history
1371 * @param in the input line
1374 input_clean (WInput
* in
)
1376 push_history (in
, in
->buffer
);
1377 in
->need_push
= TRUE
;
1378 in
->buffer
[0] = '\0';
1382 input_free_completions (in
);
1383 input_update (in
, FALSE
);
1386 /* --------------------------------------------------------------------------------------------- */
1389 input_free_completions (WInput
* in
)
1391 g_strfreev (in
->completions
);
1392 in
->completions
= NULL
;
1395 /* --------------------------------------------------------------------------------------------- */