2 Widgets for the Midnight Commander
4 Copyright (C) 1994-2019
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
);
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 str_move (in
->buffer
+ first
, in
->buffer
+ last
);
165 in
->need_push
= TRUE
;
168 /* --------------------------------------------------------------------------------------------- */
171 do_show_hist (WInput
* in
)
176 len
= get_history_length (in
->history
.list
);
178 r
= history_show (&in
->history
.list
, WIDGET (in
),
179 g_list_position (in
->history
.list
, in
->history
.list
));
182 input_assign_text (in
, r
);
186 /* Has history cleaned up or not? */
187 if (len
!= get_history_length (in
->history
.list
))
188 in
->history
.changed
= TRUE
;
191 /* --------------------------------------------------------------------------------------------- */
193 * Strip password from incomplete url (just user:pass@host without VFS prefix).
195 * @param url partial URL
196 * @return newly allocated string without password
200 input_history_strip_password (char *url
)
202 char *at
, *delim
, *colon
;
204 at
= strrchr (url
, '@');
206 return g_strdup (url
);
208 /* TODO: handle ':' and '@' in password */
210 delim
= strstr (url
, VFS_PATH_URL_DELIMITER
);
212 colon
= strchr (delim
+ strlen (VFS_PATH_URL_DELIMITER
), ':');
214 colon
= strchr (url
, ':');
216 /* if 'colon' before 'at', 'colon' delimits user and password: user:password@host */
217 /* if 'colon' after 'at', 'colon' delimits host and port: user@host:port */
218 if (colon
!= NULL
&& colon
> at
)
222 return g_strdup (url
);
225 return g_strconcat (url
, at
, (char *) NULL
);
228 /* --------------------------------------------------------------------------------------------- */
231 push_history (WInput
* in
, const char *text
)
239 t
= g_strstrip (g_strdup (text
));
242 t
= g_strdup (empty
? "" : text
);
244 if (!empty
&& in
->history
.name
!= NULL
&& in
->strip_password
)
247 We got string user:pass@host without any VFS prefixes
248 and vfs_path_to_str_flags (t, VPF_STRIP_PASSWORD) doesn't work.
249 Therefore we want to strip password in separate algorithm
251 char *url_with_stripped_password
;
253 url_with_stripped_password
= input_history_strip_password (t
);
255 t
= url_with_stripped_password
;
258 if (in
->history
.list
== NULL
|| in
->history
.list
->data
== NULL
259 || strcmp (in
->history
.list
->data
, t
) != 0 || in
->history
.changed
)
261 in
->history
.list
= list_append_unique (in
->history
.list
, t
);
262 in
->history
.current
= in
->history
.list
;
263 in
->history
.changed
= TRUE
;
268 in
->need_push
= FALSE
;
271 /* --------------------------------------------------------------------------------------------- */
274 move_buffer_backward (WInput
* in
, int start
, int end
)
279 str_len
= str_length (in
->buffer
);
280 if (start
>= str_len
|| end
> str_len
+ 1)
283 pos
= str_offset_to_pos (in
->buffer
, start
);
284 len
= str_offset_to_pos (in
->buffer
, end
) - pos
;
286 for (i
= pos
; in
->buffer
[i
+ len
- 1]; i
++)
287 in
->buffer
[i
] = in
->buffer
[i
+ len
];
290 /* --------------------------------------------------------------------------------------------- */
293 insert_char (WInput
* in
, int c_code
)
298 if (input_eval_marks (in
, &m1
, &m2
))
299 delete_region (in
, m1
, m2
);
302 return MSG_NOT_HANDLED
;
304 if (in
->charpoint
>= MB_LEN_MAX
)
307 in
->charbuf
[in
->charpoint
] = c_code
;
310 res
= str_is_valid_char (in
->charbuf
, in
->charpoint
);
314 in
->charpoint
= 0; /* broken multibyte char, skip */
318 in
->need_push
= TRUE
;
319 if (strlen (in
->buffer
) + 1 + in
->charpoint
>= in
->current_max_size
)
321 /* Expand the buffer */
325 new_length
= in
->current_max_size
+ WIDGET (in
)->cols
+ in
->charpoint
;
326 narea
= g_try_renew (char, in
->buffer
, new_length
);
330 in
->current_max_size
= new_length
;
334 if (strlen (in
->buffer
) + in
->charpoint
< in
->current_max_size
)
337 /* bytes from begin */
338 size_t ins_point
= str_offset_to_pos (in
->buffer
, in
->point
);
340 size_t rest_bytes
= strlen (in
->buffer
+ ins_point
);
342 for (i
= rest_bytes
+ 1; i
> 0; i
--)
343 in
->buffer
[ins_point
+ i
+ in
->charpoint
- 1] = in
->buffer
[ins_point
+ i
- 1];
345 memcpy (in
->buffer
+ ins_point
, in
->charbuf
, in
->charpoint
);
353 /* --------------------------------------------------------------------------------------------- */
356 beginning_of_line (WInput
* in
)
362 /* --------------------------------------------------------------------------------------------- */
365 end_of_line (WInput
* in
)
367 in
->point
= str_length (in
->buffer
);
371 /* --------------------------------------------------------------------------------------------- */
374 backward_char (WInput
* in
)
378 act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
380 in
->point
-= str_cprev_noncomb_char (&act
, in
->buffer
);
384 /* --------------------------------------------------------------------------------------------- */
387 forward_char (WInput
* in
)
391 act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
393 in
->point
+= str_cnext_noncomb_char (&act
);
397 /* --------------------------------------------------------------------------------------------- */
400 forward_word (WInput
* in
)
404 p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
405 while (p
[0] != '\0' && (str_isspace (p
) || str_ispunct (p
)))
410 while (p
[0] != '\0' && !str_isspace (p
) && !str_ispunct (p
))
417 /* --------------------------------------------------------------------------------------------- */
420 backward_word (WInput
* in
)
424 p
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
426 while (p
!= in
->buffer
)
432 if (!str_isspace (p
) && !str_ispunct (p
))
439 while (p
!= in
->buffer
)
442 if (str_isspace (p
) || str_ispunct (p
))
449 /* --------------------------------------------------------------------------------------------- */
452 backward_delete (WInput
* in
)
454 const char *act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
460 start
= in
->point
- str_cprev_noncomb_char (&act
, in
->buffer
);
461 move_buffer_backward (in
, start
, in
->point
);
463 in
->need_push
= TRUE
;
467 /* --------------------------------------------------------------------------------------------- */
470 delete_char (WInput
* in
)
475 act
= in
->buffer
+ str_offset_to_pos (in
->buffer
, in
->point
);
476 end
+= str_cnext_noncomb_char (&act
);
478 move_buffer_backward (in
, in
->point
, end
);
480 in
->need_push
= TRUE
;
483 /* --------------------------------------------------------------------------------------------- */
486 copy_region (WInput
* in
, int x_first
, int x_last
)
488 int first
= MIN (x_first
, x_last
);
489 int last
= MAX (x_first
, x_last
);
493 /* Copy selected files to clipboard */
494 mc_event_raise (MCEVENT_GROUP_FILEMANAGER
, "panel_save_current_file_to_clip_file", NULL
);
495 /* try use external clipboard utility */
496 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_file_to_ext_clip", NULL
);
500 g_free (kill_buffer
);
502 first
= str_offset_to_pos (in
->buffer
, first
);
503 last
= str_offset_to_pos (in
->buffer
, last
);
505 kill_buffer
= g_strndup (in
->buffer
+ first
, last
- first
);
507 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_text_to_file", kill_buffer
);
508 /* try use external clipboard utility */
509 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_file_to_ext_clip", NULL
);
512 /* --------------------------------------------------------------------------------------------- */
515 kill_word (WInput
* in
)
517 int old_point
= in
->point
;
521 new_point
= in
->point
;
522 in
->point
= old_point
;
524 delete_region (in
, old_point
, new_point
);
525 in
->need_push
= TRUE
;
529 /* --------------------------------------------------------------------------------------------- */
532 back_kill_word (WInput
* in
)
534 int old_point
= in
->point
;
538 new_point
= in
->point
;
539 in
->point
= old_point
;
541 delete_region (in
, old_point
, new_point
);
542 in
->need_push
= TRUE
;
545 /* --------------------------------------------------------------------------------------------- */
550 if (kill_buffer
!= NULL
)
555 for (p
= kill_buffer
; *p
!= '\0'; p
++)
556 insert_char (in
, *p
);
561 /* --------------------------------------------------------------------------------------------- */
564 kill_line (WInput
* in
)
568 chp
= str_offset_to_pos (in
->buffer
, in
->point
);
569 g_free (kill_buffer
);
570 kill_buffer
= g_strdup (&in
->buffer
[chp
]);
571 in
->buffer
[chp
] = '\0';
575 /* --------------------------------------------------------------------------------------------- */
578 clear_line (WInput
* in
)
580 in
->need_push
= TRUE
;
581 in
->buffer
[0] = '\0';
587 /* --------------------------------------------------------------------------------------------- */
590 ins_from_clip (WInput
* in
)
593 ev_clipboard_text_from_file_t event_data
;
595 /* try use external clipboard utility */
596 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_file_from_ext_clip", NULL
);
598 event_data
.text
= &p
;
599 mc_event_raise (MCEVENT_GROUP_CORE
, "clipboard_text_from_file", &event_data
);
604 for (pp
= p
; *pp
!= '\0'; pp
++)
605 insert_char (in
, *pp
);
611 /* --------------------------------------------------------------------------------------------- */
614 hist_prev (WInput
* in
)
618 if (in
->history
.list
== NULL
)
622 push_history (in
, in
->buffer
);
624 prev
= g_list_previous (in
->history
.current
);
627 input_assign_text (in
, (char *) prev
->data
);
628 in
->history
.current
= prev
;
629 in
->history
.changed
= TRUE
;
630 in
->need_push
= FALSE
;
634 /* --------------------------------------------------------------------------------------------- */
637 hist_next (WInput
* in
)
643 push_history (in
, in
->buffer
);
644 input_assign_text (in
, "");
648 if (in
->history
.list
== NULL
)
651 next
= g_list_next (in
->history
.current
);
654 input_assign_text (in
, "");
655 in
->history
.current
= in
->history
.list
;
659 input_assign_text (in
, (char *) next
->data
);
660 in
->history
.current
= next
;
661 in
->history
.changed
= TRUE
;
662 in
->need_push
= FALSE
;
666 /* --------------------------------------------------------------------------------------------- */
669 port_region_marked_for_delete (WInput
* in
)
671 in
->buffer
[0] = '\0';
677 /* --------------------------------------------------------------------------------------------- */
680 input_execute_cmd (WInput
* in
, long command
)
682 cb_ret_t res
= MSG_HANDLED
;
688 case CK_MarkToWordBegin
:
689 case CK_MarkToWordEnd
:
692 /* a highlight command like shift-arrow */
695 input_mark_cmd (in
, FALSE
); /* clear */
696 input_mark_cmd (in
, TRUE
); /* marking on */
704 input_mark_cmd (in
, FALSE
);
714 beginning_of_line (in
);
725 case CK_MarkToWordBegin
:
733 case CK_MarkToWordEnd
:
740 if (input_eval_marks (in
, &m1
, &m2
))
741 delete_region (in
, m1
, m2
);
743 backward_delete (in
);
748 port_region_marked_for_delete (in
);
753 if (input_eval_marks (in
, &m1
, &m2
))
754 delete_region (in
, m1
, m2
);
759 case CK_DeleteToWordEnd
:
762 case CK_DeleteToWordBegin
:
766 input_mark_cmd (in
, TRUE
);
769 delete_region (in
, in
->point
, MAX (in
->mark
, 0));
778 copy_region (in
, MAX (in
->mark
, 0), in
->point
);
784 m
= MAX (in
->mark
, 0);
785 copy_region (in
, m
, in
->point
);
786 delete_region (in
, in
->point
, m
);
808 res
= MSG_NOT_HANDLED
;
815 case CK_MarkToWordBegin
:
816 case CK_MarkToWordEnd
:
829 /* --------------------------------------------------------------------------------------------- */
831 /* "history_load" event handler */
833 input_load_history (const gchar
* event_group_name
, const gchar
* event_name
,
834 gpointer init_data
, gpointer data
)
836 WInput
*in
= INPUT (init_data
);
837 ev_history_load_save_t
*ev
= (ev_history_load_save_t
*) data
;
839 (void) event_group_name
;
842 in
->history
.list
= history_load (ev
->cfg
, in
->history
.name
);
843 in
->history
.current
= in
->history
.list
;
845 if (in
->init_from_history
)
847 const char *def_text
= "";
849 if (in
->history
.list
!= NULL
&& in
->history
.list
->data
!= NULL
)
850 def_text
= (const char *) in
->history
.list
->data
;
852 input_assign_text (in
, def_text
);
858 /* --------------------------------------------------------------------------------------------- */
860 /* "history_save" event handler */
862 input_save_history (const gchar
* event_group_name
, const gchar
* event_name
,
863 gpointer init_data
, gpointer data
)
865 WInput
*in
= INPUT (init_data
);
867 (void) event_group_name
;
870 if (!in
->is_password
&& (WIDGET (in
)->owner
->ret_value
!= B_CANCEL
))
872 ev_history_load_save_t
*ev
= (ev_history_load_save_t
*) data
;
874 push_history (in
, in
->buffer
);
875 if (in
->history
.changed
)
876 history_save (ev
->cfg
, in
->history
.name
, in
->history
.list
);
877 in
->history
.changed
= FALSE
;
883 /* --------------------------------------------------------------------------------------------- */
886 input_destroy (WInput
* in
)
890 fprintf (stderr
, "Internal error: null Input *\n");
894 input_free_completions (in
);
897 if (in
->history
.list
!= NULL
)
899 /* history is already saved before this moment */
900 in
->history
.list
= g_list_first (in
->history
.list
);
901 g_list_free_full (in
->history
.list
, g_free
);
903 g_free (in
->history
.name
);
905 MC_PTR_FREE (kill_buffer
);
908 /* --------------------------------------------------------------------------------------------- */
911 * Calculates the buffer index (aka "point") corresponding to some screen coordinate.
914 input_screen_to_point (const WInput
* in
, int x
)
916 x
+= in
->term_first_shown
;
921 if (x
< str_term_width1 (in
->buffer
))
922 return str_column_to_pos (in
->buffer
, x
);
924 return str_length (in
->buffer
);
927 /* --------------------------------------------------------------------------------------------- */
930 input_mouse_callback (Widget
* w
, mouse_msg_t msg
, mouse_event_t
* event
)
932 /* save point between MSG_MOUSE_DOWN and MSG_MOUSE_DRAG */
933 static int prev_point
= 0;
934 WInput
*in
= INPUT (w
);
942 if (event
->x
>= w
->cols
- HISTORY_BUTTON_WIDTH
&& should_show_history_button (in
))
946 input_mark_cmd (in
, FALSE
);
947 input_set_point (in
, input_screen_to_point (in
, event
->x
));
948 /* save point for the possible following MSG_MOUSE_DRAG action */
949 prev_point
= in
->point
;
954 /* start point: set marker using point before first MSG_MOUSE_DRAG action */
956 in
->mark
= prev_point
;
958 input_set_point (in
, input_screen_to_point (in
, event
->x
));
962 /* don't create highlight region of 0 length */
963 if (in
->mark
== in
->point
)
964 input_mark_cmd (in
, FALSE
);
969 /* --------------------------------------------------------------------------------------------- */
970 /*** public functions ****************************************************************************/
971 /* --------------------------------------------------------------------------------------------- */
973 /** Create new instance of WInput object.
974 * @param y Y coordinate
975 * @param x X coordinate
976 * @param input_colors Array of used colors
977 * @param width Widget width
978 * @param def_text Default text filled in widget
979 * @param histname Name of history
980 * @param completion_flags Flags for specify type of completions
981 * @return WInput object
984 input_new (int y
, int x
, const int *colors
, int width
, const char *def_text
,
985 const char *histname
, input_complete_t completion_flags
)
990 in
= g_new (WInput
, 1);
992 widget_init (w
, y
, x
, 1, width
, input_callback
, input_mouse_callback
);
993 w
->options
|= WOP_SELECTABLE
| WOP_IS_INPUT
| WOP_WANT_CURSOR
;
998 in
->term_first_shown
= 0;
999 in
->disable_update
= 0;
1000 in
->is_password
= FALSE
;
1001 in
->strip_password
= FALSE
;
1003 /* in->buffer will be corrected in "history_load" event handler */
1004 in
->current_max_size
= width
+ 1;
1005 in
->buffer
= g_new0 (char, in
->current_max_size
);
1007 /* init completions before input_assign_text() call */
1008 in
->completions
= NULL
;
1009 in
->completion_flags
= completion_flags
;
1011 in
->init_from_history
= (def_text
== INPUT_LAST_TEXT
);
1013 if (in
->init_from_history
|| def_text
== NULL
)
1016 input_assign_text (in
, def_text
);
1018 /* prepare to history setup */
1019 in
->history
.list
= NULL
;
1020 in
->history
.current
= NULL
;
1021 in
->history
.changed
= FALSE
;
1022 in
->history
.name
= NULL
;
1023 if ((histname
!= NULL
) && (*histname
!= '\0'))
1024 in
->history
.name
= g_strdup (histname
);
1025 /* history will be loaded later */
1032 /* --------------------------------------------------------------------------------------------- */
1035 input_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
1037 WInput
*in
= INPUT (w
);
1043 /* subscribe to "history_load" event */
1044 mc_event_add (w
->owner
->event_group
, MCEVENT_HISTORY_LOAD
, input_load_history
, w
, NULL
);
1045 /* subscribe to "history_save" event */
1046 mc_event_add (w
->owner
->event_group
, MCEVENT_HISTORY_SAVE
, input_save_history
, w
, NULL
);
1047 if (in
->label
!= NULL
)
1048 widget_set_state (WIDGET (in
->label
), WST_DISABLED
, widget_get_state (w
, WST_DISABLED
));
1052 if (parm
== XCTRL ('q'))
1055 v
= input_handle_char (in
, ascii_alpha_to_cntrl (tty_getch ()));
1060 /* Keys we want others to handle */
1061 if (parm
== KEY_UP
|| parm
== KEY_DOWN
|| parm
== ESC_CHAR
1062 || parm
== KEY_F (10) || parm
== '\n')
1063 return MSG_NOT_HANDLED
;
1065 /* When pasting multiline text, insert literal Enter */
1066 if ((parm
& ~KEY_M_MASK
) == '\n')
1069 v
= input_handle_char (in
, '\n');
1074 return input_handle_char (in
, parm
);
1077 return input_execute_cmd (in
, parm
);
1080 input_update (in
, FALSE
);
1085 if (in
->label
!= NULL
)
1086 widget_set_state (WIDGET (in
->label
), WST_DISABLED
, msg
== MSG_DISABLE
);
1090 widget_move (in
, 0, str_term_width2 (in
->buffer
, in
->point
) - in
->term_first_shown
);
1094 /* unsubscribe from "history_load" event */
1095 mc_event_del (w
->owner
->event_group
, MCEVENT_HISTORY_LOAD
, input_load_history
, w
);
1096 /* unsubscribe from "history_save" event */
1097 mc_event_del (w
->owner
->event_group
, MCEVENT_HISTORY_SAVE
, input_save_history
, w
);
1102 return widget_default_callback (w
, sender
, msg
, parm
, data
);
1106 /* --------------------------------------------------------------------------------------------- */
1109 input_set_default_colors (void)
1111 input_colors
[WINPUTC_MAIN
] = INPUT_COLOR
;
1112 input_colors
[WINPUTC_MARK
] = INPUT_MARK_COLOR
;
1113 input_colors
[WINPUTC_UNCHANGED
] = INPUT_UNCHANGED_COLOR
;
1114 input_colors
[WINPUTC_HISTORY
] = INPUT_HISTORY_COLOR
;
1117 /* --------------------------------------------------------------------------------------------- */
1120 input_handle_char (WInput
* in
, int key
)
1127 input_free_completions (in
);
1128 v
= insert_char (in
, key
);
1129 input_update (in
, TRUE
);
1134 command
= keybind_lookup_keymap_command (input_map
, key
);
1136 if (command
== CK_IgnoreKey
)
1139 return MSG_NOT_HANDLED
;
1141 port_region_marked_for_delete (in
);
1142 input_free_completions (in
);
1143 v
= insert_char (in
, key
);
1147 if (command
!= CK_Complete
)
1148 input_free_completions (in
);
1149 input_execute_cmd (in
, command
);
1152 input_update (in
, TRUE
); /* needed to clear in->first */
1155 input_update (in
, TRUE
);
1159 /* --------------------------------------------------------------------------------------------- */
1161 /* This function is a test for a special input key used in complete.c */
1162 /* Returns 0 if it is not a special key, 1 if it is a non-complete key
1163 and 2 if it is a complete key */
1165 input_key_is_in_map (WInput
* in
, int key
)
1171 command
= keybind_lookup_keymap_command (input_map
, key
);
1172 if (command
== CK_IgnoreKey
)
1175 return (command
== CK_Complete
) ? 2 : 1;
1178 /* --------------------------------------------------------------------------------------------- */
1181 input_assign_text (WInput
* in
, const char *text
)
1183 Widget
*w
= WIDGET (in
);
1184 size_t text_len
, buffer_len
;
1189 input_free_completions (in
);
1191 in
->need_push
= TRUE
;
1194 text_len
= strlen (text
);
1195 buffer_len
= 1 + MAX ((size_t) w
->cols
, text_len
);
1196 in
->current_max_size
= buffer_len
;
1197 if (buffer_len
> (size_t) w
->cols
)
1198 in
->buffer
= g_realloc (in
->buffer
, buffer_len
);
1199 memmove (in
->buffer
, text
, text_len
+ 1);
1200 in
->point
= str_length (in
->buffer
);
1201 input_update (in
, TRUE
);
1204 /* --------------------------------------------------------------------------------------------- */
1207 input_is_empty (const WInput
* in
)
1209 return (in
== NULL
|| in
->buffer
== NULL
|| in
->buffer
[0] == '\0');
1212 /* --------------------------------------------------------------------------------------------- */
1214 /* Inserts text in input line */
1216 input_insert (WInput
* in
, const char *text
, gboolean insert_extra_space
)
1218 input_disable_update (in
);
1219 while (*text
!= '\0')
1220 input_handle_char (in
, (unsigned char) *text
++); /* unsigned extension char->int */
1221 if (insert_extra_space
)
1222 input_handle_char (in
, ' ');
1223 input_enable_update (in
);
1224 input_update (in
, TRUE
);
1227 /* --------------------------------------------------------------------------------------------- */
1230 input_set_point (WInput
* in
, int pos
)
1234 max_pos
= str_length (in
->buffer
);
1235 pos
= MIN (pos
, max_pos
);
1236 if (pos
!= in
->point
)
1237 input_free_completions (in
);
1240 input_update (in
, TRUE
);
1243 /* --------------------------------------------------------------------------------------------- */
1246 input_update (WInput
* in
, gboolean clear_first
)
1248 Widget
*w
= WIDGET (in
);
1249 int has_history
= 0;
1254 if (in
->disable_update
!= 0)
1257 /* don't draw widget not put into dialog */
1258 if (w
->owner
== NULL
|| !widget_get_state (WIDGET (w
->owner
), WST_ACTIVE
))
1261 if (should_show_history_button (in
))
1262 has_history
= HISTORY_BUTTON_WIDTH
;
1264 buf_len
= str_length (in
->buffer
);
1266 /* Adjust the mark */
1267 in
->mark
= MIN (in
->mark
, buf_len
);
1269 pw
= str_term_width2 (in
->buffer
, in
->point
);
1271 /* Make the point visible */
1272 if ((pw
< in
->term_first_shown
) || (pw
>= in
->term_first_shown
+ w
->cols
- has_history
))
1274 in
->term_first_shown
= pw
- (w
->cols
/ 3);
1275 if (in
->term_first_shown
< 0)
1276 in
->term_first_shown
= 0;
1279 if (has_history
!= 0)
1280 draw_history_button (in
);
1282 if (widget_get_state (w
, WST_DISABLED
))
1283 tty_setcolor (DISABLED_COLOR
);
1285 tty_setcolor (in
->color
[WINPUTC_UNCHANGED
]);
1287 tty_setcolor (in
->color
[WINPUTC_MAIN
]);
1289 widget_move (in
, 0, 0);
1291 if (!in
->is_password
)
1294 tty_print_string (str_term_substring (in
->buffer
, in
->term_first_shown
,
1295 w
->cols
- has_history
));
1300 if (input_eval_marks (in
, &m1
, &m2
))
1302 tty_setcolor (in
->color
[WINPUTC_MAIN
]);
1303 cp
= str_term_substring (in
->buffer
, in
->term_first_shown
, w
->cols
- has_history
);
1304 tty_print_string (cp
);
1305 tty_setcolor (in
->color
[WINPUTC_MARK
]);
1306 if (m1
< in
->term_first_shown
)
1308 widget_move (in
, 0, 0);
1309 tty_print_string (str_term_substring
1310 (in
->buffer
, in
->term_first_shown
,
1311 m2
- in
->term_first_shown
));
1315 int sel_width
, buf_width
;
1317 widget_move (in
, 0, m1
- in
->term_first_shown
);
1318 buf_width
= str_term_width2 (in
->buffer
, m1
);
1320 MIN (m2
- m1
, (w
->cols
- has_history
) - (buf_width
- in
->term_first_shown
));
1321 tty_print_string (str_term_substring (in
->buffer
, m1
, sel_width
));
1330 cp
= str_term_substring (in
->buffer
, in
->term_first_shown
, w
->cols
- has_history
);
1331 tty_setcolor (in
->color
[WINPUTC_MAIN
]);
1332 for (i
= 0; i
< w
->cols
- has_history
; i
++)
1334 if (i
< (buf_len
- in
->term_first_shown
) && cp
[0] != '\0')
1335 tty_print_char ('*');
1337 tty_print_char (' ');
1339 str_cnext_char (&cp
);
1347 /* --------------------------------------------------------------------------------------------- */
1350 input_enable_update (WInput
* in
)
1352 in
->disable_update
--;
1353 input_update (in
, FALSE
);
1356 /* --------------------------------------------------------------------------------------------- */
1359 input_disable_update (WInput
* in
)
1361 in
->disable_update
++;
1364 /* --------------------------------------------------------------------------------------------- */
1367 * Cleans the input line and adds the current text to the history
1369 * @param in the input line
1372 input_clean (WInput
* in
)
1374 push_history (in
, in
->buffer
);
1375 in
->need_push
= TRUE
;
1376 in
->buffer
[0] = '\0';
1380 input_free_completions (in
);
1381 input_update (in
, FALSE
);
1384 /* --------------------------------------------------------------------------------------------- */
1387 input_free_completions (WInput
* in
)
1389 g_strfreev (in
->completions
);
1390 in
->completions
= NULL
;
1393 /* --------------------------------------------------------------------------------------------- */