patches by Rostislav Beneš: mc-06-input
in input widget I made a lot of changes: 1. rename some members in WInput to reflect more their functions (field_len -> field_width, ...) 2. buffer for reading multibytes characters - charbuf, (taken from UTF-8 patch) 3. modified insert_char to accept mulstibytes characters, drawing changed 4. works only with valid strings, str_fix_string used to assure that input->buffer is valid changes in complete.c: - some iteration strings with ++/-- replaced with str_next_char, str_prev_char, where was needed. ++ was offset oriented, but str_next_char use directly referecne (char *), so result is not extra beatiful in every cases - other buffer for multibytes characters - complete only valid filenames
Этот коммит содержится в:
родитель
9450950fd4
Коммит
7f71be0d63
246
src/complete.c
246
src/complete.c
@ -41,6 +41,7 @@
|
||||
#include "complete.h"
|
||||
#include "main.h"
|
||||
#include "key.h" /* XCTRL and ALT macros */
|
||||
#include "strutil.h"
|
||||
|
||||
typedef char *CompletionFunction (char *, int);
|
||||
|
||||
@ -97,6 +98,8 @@ filename_completion_function (char *text, int state)
|
||||
/* Now that we have some state, we can read the directory. */
|
||||
|
||||
while (directory && (entry = mc_readdir (directory))){
|
||||
if (!str_is_valid_string (entry->d_name)) continue;
|
||||
|
||||
/* Special case for no filename.
|
||||
All entries except "." and ".." match. */
|
||||
if (!filename_len){
|
||||
@ -273,20 +276,24 @@ static void fetch_hosts (const char *filename)
|
||||
{
|
||||
FILE *file = fopen (filename, "r");
|
||||
char buffer[256], *name;
|
||||
register int i, start;
|
||||
char *start;
|
||||
char *bi;
|
||||
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
while (fgets (buffer, 255, file) != NULL){
|
||||
/* Skip to first character. */
|
||||
for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++);
|
||||
for (bi = buffer;
|
||||
bi[0] != '\0' && str_isspace (bi);
|
||||
str_next_char (&bi));
|
||||
|
||||
/* Ignore comments... */
|
||||
if (buffer[i] == '#')
|
||||
if (bi[0] == '#')
|
||||
continue;
|
||||
/* Handle $include. */
|
||||
if (!strncmp (buffer + i, "$include ", 9)){
|
||||
char *includefile = buffer + i + 9;
|
||||
if (!strncmp (bi, "$include ", 9)){
|
||||
char *includefile = bi + 9;
|
||||
char *t;
|
||||
|
||||
/* Find start of filename. */
|
||||
@ -295,8 +302,8 @@ static void fetch_hosts (const char *filename)
|
||||
t = includefile;
|
||||
|
||||
/* Find end of filename. */
|
||||
while (*t && !cr_whitespace (*t))
|
||||
t++;
|
||||
while (t[0] != '\0' && !str_isspace (t))
|
||||
str_next_char (&t);
|
||||
*t = '\0';
|
||||
|
||||
fetch_hosts (includefile);
|
||||
@ -304,19 +311,22 @@ static void fetch_hosts (const char *filename)
|
||||
}
|
||||
|
||||
/* Skip IP #s. */
|
||||
while (buffer[i] && !cr_whitespace (buffer[i]))
|
||||
i++;
|
||||
while (bi[0] != '\0' && !str_isspace (bi))
|
||||
str_next_char (&bi);
|
||||
|
||||
/* Get the host names separated by white space. */
|
||||
while (buffer[i] && buffer[i] != '#'){
|
||||
while (buffer[i] && cr_whitespace (buffer[i]))
|
||||
i++;
|
||||
if (buffer[i] == '#')
|
||||
while (bi[0] != '\0' && bi[0] != '#'){
|
||||
while (bi[0] != '\0' && str_isspace (bi))
|
||||
str_next_char (&bi);
|
||||
if (bi[0] == '#')
|
||||
continue;
|
||||
for (start = i; buffer[i] && !cr_whitespace (buffer[i]); i++);
|
||||
if (i - start == 0)
|
||||
continue;
|
||||
name = g_strndup (buffer + start, i - start);
|
||||
for (start = bi;
|
||||
bi[0] != '\0' && !str_isspace (bi);
|
||||
str_next_char (&bi));
|
||||
|
||||
if (bi - start == 0) continue;
|
||||
|
||||
name = g_strndup (start, bi - start);
|
||||
{
|
||||
char **host_p;
|
||||
|
||||
@ -566,19 +576,30 @@ completion_matches (char *text, CompletionFunction entry_function)
|
||||
j = i + 1;
|
||||
while (j < matches + 1)
|
||||
{
|
||||
register int c1, c2, si;
|
||||
char *si, *sj;
|
||||
char *ni, *nj;
|
||||
|
||||
for (si = 0;(c1 = match_list [i][si]) && (c2 = match_list [j][si]); si++)
|
||||
if (c1 != c2) break;
|
||||
for (si = match_list[i], sj = match_list[j];
|
||||
si[0] && sj[0];) {
|
||||
|
||||
if (!c1 && !match_list [j][si]){ /* Two equal strings */
|
||||
ni = str_get_next_char (si);
|
||||
nj = str_get_next_char (sj);
|
||||
|
||||
if (ni - si != nj - sj) break;
|
||||
if (strncmp (si, sj, ni - si) != 0) break;
|
||||
|
||||
si = ni;
|
||||
sj = nj;
|
||||
}
|
||||
|
||||
if (si[0] == '\0' && sj[0] == '\0'){ /* Two equal strings */
|
||||
g_free (match_list [j]);
|
||||
j++;
|
||||
if (j > matches)
|
||||
break;
|
||||
continue; /* Look for a run of equal strings */
|
||||
} else
|
||||
if (low > si) low = si;
|
||||
if (low > si - match_list[i]) low = si - match_list[i];
|
||||
if (i + 1 != j) /* So there's some gap */
|
||||
match_list [i + 1] = match_list [j];
|
||||
i++; j++;
|
||||
@ -598,7 +619,8 @@ completion_matches (char *text, CompletionFunction entry_function)
|
||||
static int
|
||||
check_is_cd (const char *text, int start, int flags)
|
||||
{
|
||||
const char *p, *q;
|
||||
char *p, *q;
|
||||
int test = 0;
|
||||
|
||||
if (flags & INPUT_COMPLETE_CD)
|
||||
return 1;
|
||||
@ -607,14 +629,18 @@ check_is_cd (const char *text, int start, int flags)
|
||||
return 0;
|
||||
|
||||
/* Skip initial spaces */
|
||||
p = text;
|
||||
q = text + start;
|
||||
while (p < q && *p && isspace ((unsigned char) *p))
|
||||
p++;
|
||||
p = (char*)text;
|
||||
q = (char*)text + start;
|
||||
while (p < q && p[0] != '\0' && str_isspace (p))
|
||||
str_next_char (&p);
|
||||
|
||||
/* Check if the command is "cd" and the cursor is after it */
|
||||
if (p[0] == 'c' && p[1] == 'd' && isspace ((unsigned char) p[2])
|
||||
&& (p + 2 < q))
|
||||
text+= p[0] == 'c';
|
||||
str_next_char (&p);
|
||||
text+= p[0] == 'd';
|
||||
str_next_char (&p);
|
||||
text+= str_isspace (p);
|
||||
if (test == 3 && (p < q))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@ -624,44 +650,44 @@ check_is_cd (const char *text, int start, int flags)
|
||||
static char **
|
||||
try_complete (char *text, int *start, int *end, int flags)
|
||||
{
|
||||
int in_command_position = 0, i;
|
||||
char *word, c;
|
||||
int in_command_position = 0;
|
||||
char *word;
|
||||
char **matches = NULL;
|
||||
const char *command_separator_chars = ";|&{(`";
|
||||
char *p = NULL, *q = NULL, *r = NULL;
|
||||
int is_cd = check_is_cd (text, *start, flags);
|
||||
char *ti;
|
||||
|
||||
ignore_filenames = 0;
|
||||
c = text [*end];
|
||||
text [*end] = 0;
|
||||
word = g_strdup (text + *start);
|
||||
text [*end] = c;
|
||||
word = g_strndup (text + *start, *end - *start);
|
||||
|
||||
/* Determine if this could be a command word. It is if it appears at
|
||||
the start of the line (ignoring preceding whitespace), or if it
|
||||
appears after a character that separates commands. And we have to
|
||||
be in a INPUT_COMPLETE_COMMANDS flagged Input line. */
|
||||
if (!is_cd && (flags & INPUT_COMPLETE_COMMANDS)){
|
||||
i = *start - 1;
|
||||
while (i > -1 && (text[i] == ' ' || text[i] == '\t'))
|
||||
i--;
|
||||
if (i < 0)
|
||||
ti = str_get_prev_char (&text[*start]);
|
||||
while (ti > text && (ti[0] == ' ' || ti[0] == '\t'))
|
||||
str_prev_char (&ti);
|
||||
|
||||
if (ti <= text&& (ti[0] == ' ' || ti[0] == '\t'))
|
||||
in_command_position++;
|
||||
else if (strchr (command_separator_chars, text[i])){
|
||||
else if (strchr (command_separator_chars, ti[0])){
|
||||
register int this_char, prev_char;
|
||||
|
||||
in_command_position++;
|
||||
|
||||
if (i){
|
||||
if (ti > text){
|
||||
/* Handle the two character tokens `>&', `<&', and `>|'.
|
||||
We are not in a command position after one of these. */
|
||||
this_char = text[i];
|
||||
prev_char = text[i - 1];
|
||||
this_char = ti[0];
|
||||
prev_char = str_get_prev_char (ti)[0];
|
||||
|
||||
if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) ||
|
||||
(this_char == '|' && prev_char == '>'))
|
||||
in_command_position = 0;
|
||||
else if (i > 0 && text [i-1] == '\\') /* Quoted */
|
||||
|
||||
else if (ti > text && str_get_prev_char (ti)[0] == '\\') /* Quoted */
|
||||
in_command_position = 0;
|
||||
}
|
||||
}
|
||||
@ -675,15 +701,15 @@ try_complete (char *text, int *start, int *end, int flags)
|
||||
r = strrchr (word, '@');
|
||||
if (q && q [1] == '(' && INPUT_COMPLETE_COMMANDS){
|
||||
if (q > p)
|
||||
p = q + 1;
|
||||
p = str_get_next_char (q);
|
||||
q = NULL;
|
||||
}
|
||||
|
||||
/* Command substitution? */
|
||||
if (p > q && p > r){
|
||||
matches = completion_matches (p + 1, command_completion_function);
|
||||
matches = completion_matches (str_get_next_char (p), command_completion_function);
|
||||
if (matches)
|
||||
*start += p + 1 - word;
|
||||
*start += str_get_next_char (p) - word;
|
||||
}
|
||||
|
||||
/* Variable name? */
|
||||
@ -721,9 +747,9 @@ try_complete (char *text, int *start, int *end, int flags)
|
||||
if (!matches && is_cd && *word != PATH_SEP && *word != '~'){
|
||||
char *p, *q = text + *start;
|
||||
|
||||
for (p = text; *p && p < q && (*p == ' ' || *p == '\t'); p++);
|
||||
for (p = text; *p && p < q && (*p == ' ' || *p == '\t'); str_next_char (&p));
|
||||
if (!strncmp (p, "cd", 2))
|
||||
for (p += 2; *p && p < q && (*p == ' ' || *p == '\t'); p++);
|
||||
for (p += 2; *p && p < q && (*p == ' ' || *p == '\t'); str_next_char (&p));
|
||||
if (p == q){
|
||||
char * const cdpath_ref = g_strdup (getenv ("CDPATH"));
|
||||
char *cdpath = cdpath_ref;
|
||||
@ -747,7 +773,7 @@ try_complete (char *text, int *start, int *end, int flags)
|
||||
g_free (r);
|
||||
}
|
||||
*s = c;
|
||||
cdpath = s + 1;
|
||||
cdpath = str_get_next_char (s);
|
||||
}
|
||||
g_free (cdpath_ref);
|
||||
}
|
||||
@ -776,49 +802,57 @@ static WInput *input;
|
||||
static int min_end;
|
||||
static int start, end;
|
||||
|
||||
static int insert_text (WInput *in, char *text, ssize_t len)
|
||||
static int insert_text (WInput *in, char *text, ssize_t size)
|
||||
{
|
||||
len = min (len, (ssize_t) strlen (text)) + start - end;
|
||||
if (strlen (in->buffer) + len >= (size_t) in->current_max_len){
|
||||
int buff_len = str_length (in->buffer);
|
||||
|
||||
size = min (size, (ssize_t) strlen (text)) + start - end;
|
||||
if (strlen (in->buffer) + size >= (size_t) in->current_max_size){
|
||||
/* Expand the buffer */
|
||||
char *narea = g_realloc (in->buffer, in->current_max_len + len + in->field_len);
|
||||
char *narea = g_realloc (in->buffer, in->current_max_size
|
||||
+ size + in->field_width);
|
||||
if (narea){
|
||||
in->buffer = narea;
|
||||
in->current_max_len += len + in->field_len;
|
||||
in->current_max_size += size + in->field_width;
|
||||
}
|
||||
}
|
||||
if (strlen (in->buffer)+1 < (size_t) in->current_max_len){
|
||||
if (len > 0){
|
||||
if (strlen (in->buffer)+1 < (size_t) in->current_max_size){
|
||||
if (size > 0){
|
||||
int i = strlen (&in->buffer [end]);
|
||||
for (; i >= 0; i--)
|
||||
in->buffer [end + len + i] = in->buffer [end + i];
|
||||
} else if (len < 0){
|
||||
char *p = in->buffer + end + len, *q = in->buffer + end;
|
||||
in->buffer [end + size + i] = in->buffer [end + i];
|
||||
} else if (size < 0){
|
||||
char *p = in->buffer + end + size, *q = in->buffer + end;
|
||||
while (*q)
|
||||
*(p++) = *(q++);
|
||||
*p = 0;
|
||||
}
|
||||
memcpy (in->buffer + start, text, len - start + end);
|
||||
in->point += len;
|
||||
memcpy (in->buffer + start, text, size - start + end);
|
||||
in->point+= str_length (in->buffer) - buff_len;
|
||||
update_input (in, 1);
|
||||
end += len;
|
||||
end+= size;
|
||||
}
|
||||
return len != 0;
|
||||
return size != 0;
|
||||
}
|
||||
|
||||
static cb_ret_t
|
||||
query_callback (Dlg_head *h, dlg_msg_t msg, int parm)
|
||||
{
|
||||
static char buff[MB_LEN_MAX] = "";
|
||||
static int bl = 0;
|
||||
|
||||
switch (msg) {
|
||||
case DLG_KEY:
|
||||
switch (parm) {
|
||||
case KEY_LEFT:
|
||||
case KEY_RIGHT:
|
||||
bl = 0;
|
||||
h->ret_value = 0;
|
||||
dlg_stop (h);
|
||||
return MSG_HANDLED;
|
||||
|
||||
case KEY_BACKSPACE:
|
||||
bl = 0;
|
||||
if (end == min_end) {
|
||||
h->ret_value = 0;
|
||||
dlg_stop (h);
|
||||
@ -828,13 +862,13 @@ query_callback (Dlg_head *h, dlg_msg_t msg, int parm)
|
||||
|
||||
e1 = e = ((WListbox *) (h->current))->list;
|
||||
do {
|
||||
if (!strncmp
|
||||
(input->buffer + start, e1->text,
|
||||
end - start - 1)) {
|
||||
listbox_select_entry ((WListbox *) (h->current),
|
||||
e1);
|
||||
if (!strncmp (input->buffer + start,
|
||||
e1->text, end - start - 1)) {
|
||||
|
||||
listbox_select_entry ((WListbox *) (h->current), e1);
|
||||
end = str_get_prev_char (&(input->buffer[end]))
|
||||
- input->buffer;
|
||||
handle_char (input, parm);
|
||||
end--;
|
||||
send_message (h->current, WIDGET_DRAW, 0);
|
||||
break;
|
||||
}
|
||||
@ -844,7 +878,8 @@ query_callback (Dlg_head *h, dlg_msg_t msg, int parm)
|
||||
return MSG_HANDLED;
|
||||
|
||||
default:
|
||||
if (parm > 0xff || !is_printable (parm)) {
|
||||
if (parm < 32 || parm > 256) {
|
||||
bl = 0;
|
||||
if (is_in_input_map (input, parm) == 2) {
|
||||
if (end == min_end)
|
||||
return MSG_HANDLED;
|
||||
@ -860,21 +895,43 @@ query_callback (Dlg_head *h, dlg_msg_t msg, int parm)
|
||||
int low = 4096;
|
||||
char *last_text = NULL;
|
||||
|
||||
buff[bl] = (char) parm;
|
||||
bl++;
|
||||
buff[bl] = '\0';
|
||||
switch (str_is_valid_char (buff, bl)) {
|
||||
case -1:
|
||||
bl = 0;
|
||||
case -2:
|
||||
return MSG_HANDLED;
|
||||
}
|
||||
|
||||
e1 = e = ((WListbox *) (h->current))->list;
|
||||
do {
|
||||
if (!strncmp
|
||||
(input->buffer + start, e1->text, end - start)) {
|
||||
if (e1->text[end - start] == parm) {
|
||||
if (need_redraw) {
|
||||
register int c1, c2, si;
|
||||
if (!strncmp (input->buffer + start,
|
||||
e1->text, end - start)) {
|
||||
|
||||
if (strncmp (&e1->text[end - start], buff, bl) == 0) {
|
||||
if (need_redraw) {
|
||||
char *si, *sl;
|
||||
char *ni, *nl;
|
||||
si = &(e1->text[end - start]);
|
||||
sl = &(last_text[end - start]);
|
||||
|
||||
for (; si[0] != '\0' && sl[0] != '\0';) {
|
||||
|
||||
ni = str_get_next_char (si);
|
||||
nl = str_get_next_char (sl);
|
||||
|
||||
if (ni - si != nl - sl) break;
|
||||
if (strncmp (si, sl, ni - si) != 0) break;
|
||||
|
||||
si = ni;
|
||||
sl = nl;
|
||||
}
|
||||
|
||||
if (low > si - &e1->text[start])
|
||||
low = si - &e1->text[start];
|
||||
|
||||
for (si = end - start + 1;
|
||||
(c1 = last_text[si])
|
||||
&& (c2 = e1->text[si]); si++)
|
||||
if (c1 != c2)
|
||||
break;
|
||||
if (low > si)
|
||||
low = si;
|
||||
last_text = e1->text;
|
||||
need_redraw = 2;
|
||||
} else {
|
||||
@ -895,6 +952,7 @@ query_callback (Dlg_head *h, dlg_msg_t msg, int parm)
|
||||
h->ret_value = B_ENTER;
|
||||
dlg_stop (h);
|
||||
}
|
||||
bl = 0;
|
||||
}
|
||||
return MSG_HANDLED;
|
||||
}
|
||||
@ -911,15 +969,19 @@ query_callback (Dlg_head *h, dlg_msg_t msg, int parm)
|
||||
static int
|
||||
complete_engine (WInput *in, int what_to_do)
|
||||
{
|
||||
if (in->completions && in->point != end)
|
||||
int s;
|
||||
|
||||
if (in->completions && (str_offset_to_pos (in->buffer, in->point)) != end)
|
||||
free_completions (in);
|
||||
if (!in->completions){
|
||||
end = in->point;
|
||||
for (start = end ? end - 1 : 0; start > -1; start--)
|
||||
if (strchr (" \t;|<>", in->buffer [start]))
|
||||
end = str_offset_to_pos (in->buffer, in->point);
|
||||
for (s = in->point ? in->point - 1 : 0; s >= 0; s--) {
|
||||
start = str_offset_to_pos (in->buffer, s);
|
||||
if (strchr (" \t;|<>", in->buffer [start])) {
|
||||
if (start < end) start = str_offset_to_pos (in->buffer, s + 1);
|
||||
break;
|
||||
if (start < end)
|
||||
start++;
|
||||
}
|
||||
}
|
||||
in->completions = try_complete (in->buffer, &start, &end, in->completion_flags);
|
||||
}
|
||||
if (in->completions){
|
||||
@ -941,7 +1003,7 @@ complete_engine (WInput *in, int what_to_do)
|
||||
WListbox *query_list;
|
||||
|
||||
for (p=in->completions + 1; *p; count++, p++)
|
||||
if ((i = strlen (*p)) > maxlen)
|
||||
if ((i = str_term_width1 (*p)) > maxlen)
|
||||
maxlen = i;
|
||||
start_x = in->widget.x;
|
||||
start_y = in->widget.y;
|
||||
@ -957,7 +1019,7 @@ complete_engine (WInput *in, int what_to_do)
|
||||
h = LINES - start_y - 1;
|
||||
}
|
||||
}
|
||||
x = start - in->first_shown - 2 + start_x;
|
||||
x = start - in->term_first_shown - 2 + start_x;
|
||||
w = maxlen + 4;
|
||||
if (x + w > COLS)
|
||||
x = COLS - w;
|
||||
@ -999,6 +1061,8 @@ void complete (WInput *in)
|
||||
{
|
||||
int engine_flags;
|
||||
|
||||
if (!str_is_valid_string (in->buffer)) return;
|
||||
|
||||
if (in->completions)
|
||||
engine_flags = DO_QUERY;
|
||||
else
|
||||
|
278
src/widget.c
278
src/widget.c
@ -789,27 +789,21 @@ gauge_new (int y, int x, int shown, int max, int current)
|
||||
#endif
|
||||
|
||||
#define should_show_history_button(in) \
|
||||
(in->history && in->field_len > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
|
||||
(in->history && in->field_width > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
|
||||
|
||||
static void draw_history_button (WInput * in)
|
||||
{
|
||||
char c;
|
||||
c = in->history->next ? (in->history->prev ? '|' : 'v') : '^';
|
||||
widget_move (&in->widget, 0, in->field_len - HISTORY_BUTTON_WIDTH);
|
||||
widget_move (&in->widget, 0, in->field_width - HISTORY_BUTTON_WIDTH);
|
||||
#ifdef LARGE_HISTORY_BUTTON
|
||||
{
|
||||
Dlg_head *h;
|
||||
h = in->widget.parent;
|
||||
#if 0
|
||||
attrset (NORMALC); /* button has the same color as other buttons */
|
||||
addstr ("[ ]");
|
||||
attrset (HOT_NORMALC);
|
||||
#else
|
||||
attrset (NORMAL_COLOR);
|
||||
addstr ("[ ]");
|
||||
/* Too distracting: attrset (MARKED_COLOR); */
|
||||
#endif
|
||||
widget_move (&in->widget, 0, in->field_len - HISTORY_BUTTON_WIDTH + 1);
|
||||
widget_move (&in->widget, 0, in->field_width - HISTORY_BUTTON_WIDTH + 1);
|
||||
addch (c);
|
||||
}
|
||||
#else
|
||||
@ -829,9 +823,10 @@ void
|
||||
update_input (WInput *in, int clear_first)
|
||||
{
|
||||
int has_history = 0;
|
||||
int i, j;
|
||||
unsigned char c;
|
||||
int buf_len = strlen (in->buffer);
|
||||
int i;
|
||||
int buf_len = str_length (in->buffer);
|
||||
const char *cp;
|
||||
int pw;
|
||||
|
||||
if (should_show_history_button (in))
|
||||
has_history = HISTORY_BUTTON_WIDTH;
|
||||
@ -839,12 +834,15 @@ update_input (WInput *in, int clear_first)
|
||||
if (in->disable_update)
|
||||
return;
|
||||
|
||||
pw = str_term_width2 (in->buffer, in->point);
|
||||
|
||||
/* Make the point visible */
|
||||
if ((in->point < in->first_shown) ||
|
||||
(in->point >= in->first_shown+in->field_len - has_history)){
|
||||
in->first_shown = in->point - (in->field_len / 3);
|
||||
if (in->first_shown < 0)
|
||||
in->first_shown = 0;
|
||||
if ((pw < in->term_first_shown) ||
|
||||
(pw >= in->term_first_shown + in->field_width - has_history)) {
|
||||
|
||||
in->term_first_shown = pw - (in->field_width / 3);
|
||||
if (in->term_first_shown < 0)
|
||||
in->term_first_shown = 0;
|
||||
}
|
||||
|
||||
/* Adjust the mark */
|
||||
@ -857,28 +855,29 @@ update_input (WInput *in, int clear_first)
|
||||
attrset (in->color);
|
||||
|
||||
widget_move (&in->widget, 0, 0);
|
||||
for (i = 0; i < in->field_len - has_history; i++)
|
||||
addch (' ');
|
||||
widget_move (&in->widget, 0, 0);
|
||||
|
||||
for (i = 0, j = in->first_shown; i < in->field_len - has_history && in->buffer [j]; i++){
|
||||
c = in->buffer [j++];
|
||||
c = is_printable (c) ? c : '.';
|
||||
if (in->is_password)
|
||||
c = '*';
|
||||
addch (c);
|
||||
if (!in->is_password) {
|
||||
addstr (str_term_substring (in->buffer, in->term_first_shown,
|
||||
in->field_width - has_history));
|
||||
} else {
|
||||
cp = in->buffer;
|
||||
for (i = -in->term_first_shown; i < in->field_width - has_history; i++){
|
||||
if (i >= 0) {
|
||||
addch ((cp[0] != '\0') ? '*' : ' ');
|
||||
}
|
||||
if (cp[0] != '\0') str_cnext_char (&cp);
|
||||
}
|
||||
}
|
||||
widget_move (&in->widget, 0, in->point - in->first_shown);
|
||||
|
||||
if (clear_first)
|
||||
in->first = 0;
|
||||
}
|
||||
|
||||
void
|
||||
winput_set_origin (WInput *in, int x, int field_len)
|
||||
winput_set_origin (WInput *in, int x, int field_width)
|
||||
{
|
||||
in->widget.x = x;
|
||||
in->field_len = in->widget.cols = field_len;
|
||||
in->field_width = in->widget.cols = field_width;
|
||||
update_input (in, 0);
|
||||
}
|
||||
|
||||
@ -997,11 +996,7 @@ history_put (const char *input_name, GList *h)
|
||||
static const char *
|
||||
i18n_htitle (void)
|
||||
{
|
||||
static const char *history_title = NULL;
|
||||
|
||||
if (history_title == NULL)
|
||||
history_title = _(" History ");
|
||||
return history_title;
|
||||
return _(" History ");
|
||||
}
|
||||
|
||||
static WLEntry *listbox_select_pos (WListbox *l, WLEntry *base, int
|
||||
@ -1021,7 +1016,7 @@ char *
|
||||
show_hist (GList *history, int widget_x, int widget_y)
|
||||
{
|
||||
GList *hi, *z;
|
||||
size_t maxlen = strlen (i18n_htitle ()), i, count = 0;
|
||||
size_t maxlen = str_term_width1 (i18n_htitle ()), i, count = 0;
|
||||
int x, y, w, h;
|
||||
char *q, *r = 0;
|
||||
Dlg_head *query_dlg;
|
||||
@ -1034,7 +1029,7 @@ show_hist (GList *history, int widget_x, int widget_y)
|
||||
z = g_list_first (history);
|
||||
hi = z;
|
||||
while (hi) {
|
||||
if ((i = strlen ((char *) hi->data)) > maxlen)
|
||||
if ((i = str_term_width1 ((char *) hi->data)) > maxlen)
|
||||
maxlen = i;
|
||||
count++;
|
||||
hi = g_list_next (hi);
|
||||
@ -1202,37 +1197,75 @@ new_input (WInput *in)
|
||||
if (in->buffer)
|
||||
push_history (in, in->buffer);
|
||||
in->need_push = 1;
|
||||
in->buffer [0] = 0;
|
||||
in->buffer[0] = '\0';
|
||||
in->point = 0;
|
||||
in->charpoint = 0;
|
||||
in->mark = 0;
|
||||
free_completions (in);
|
||||
update_input (in, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
move_buffer_backward (WInput *in, int start, int end)
|
||||
{
|
||||
int i, pos, len;
|
||||
int str_len = str_length (in->buffer);
|
||||
if (start >= str_len || end > str_len + 1) return;
|
||||
|
||||
pos = str_offset_to_pos (in->buffer, start);
|
||||
len = str_offset_to_pos (in->buffer, end) - pos;
|
||||
|
||||
for (i = pos; in->buffer[i + len - 1]; i++)
|
||||
in->buffer[i] = in->buffer[i + len];
|
||||
}
|
||||
|
||||
static cb_ret_t
|
||||
insert_char (WInput *in, int c_code)
|
||||
{
|
||||
size_t i;
|
||||
int res;
|
||||
|
||||
if (c_code == -1)
|
||||
return MSG_NOT_HANDLED;
|
||||
|
||||
if (in->charpoint >= MB_LEN_MAX) return 1;
|
||||
|
||||
in->charbuf[in->charpoint] = c_code;
|
||||
in->charpoint++;
|
||||
|
||||
res = str_is_valid_char (in->charbuf, in->charpoint);
|
||||
if (res < 0) {
|
||||
if (res != -2) in->charpoint = 0; /* broken multibyte char, skip */
|
||||
return 1;
|
||||
}
|
||||
|
||||
in->need_push = 1;
|
||||
if (strlen (in->buffer)+1 == (size_t) in->current_max_len){
|
||||
if (strlen (in->buffer) + 1 + in->charpoint >= in->current_max_size){
|
||||
/* Expand the buffer */
|
||||
char *narea = g_realloc (in->buffer, in->current_max_len + in->field_len);
|
||||
size_t new_length = in->current_max_size +
|
||||
in->field_width + in->charpoint;
|
||||
char *narea = g_try_renew (char, in->buffer, new_length);
|
||||
if (narea){
|
||||
in->buffer = narea;
|
||||
in->current_max_len += in->field_len;
|
||||
in->current_max_size = new_length;
|
||||
}
|
||||
}
|
||||
if (strlen (in->buffer)+1 < (size_t) in->current_max_len){
|
||||
size_t l = strlen (&in->buffer [in->point]);
|
||||
for (i = l+1; i > 0; i--)
|
||||
in->buffer [in->point+i] = in->buffer [in->point+i-1];
|
||||
in->buffer [in->point] = c_code;
|
||||
|
||||
if (strlen (in->buffer) + in->charpoint < in->current_max_size) {
|
||||
/* bytes from begin */
|
||||
size_t ins_point = str_offset_to_pos (in->buffer, in->point);
|
||||
/* move chars */
|
||||
size_t rest_bytes = strlen (in->buffer + ins_point);
|
||||
|
||||
for (i = rest_bytes + 1; i > 0; i--)
|
||||
in->buffer[ins_point + i + in->charpoint - 1] =
|
||||
in->buffer[ins_point + i - 1];
|
||||
|
||||
memcpy(in->buffer + ins_point, in->charbuf, in->charpoint);
|
||||
in->point++;
|
||||
}
|
||||
|
||||
in->charpoint = 0;
|
||||
return MSG_HANDLED;
|
||||
}
|
||||
|
||||
@ -1240,54 +1273,70 @@ static void
|
||||
beginning_of_line (WInput *in)
|
||||
{
|
||||
in->point = 0;
|
||||
in->charpoint = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
end_of_line (WInput *in)
|
||||
{
|
||||
in->point = strlen (in->buffer);
|
||||
in->point = str_length (in->buffer);
|
||||
in->charpoint = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
backward_char (WInput *in)
|
||||
{
|
||||
if (in->point)
|
||||
in->point--;
|
||||
const char *act = in->buffer + str_offset_to_pos (in->buffer, in->point);
|
||||
|
||||
if (in->point > 0) {
|
||||
in->point-= str_cprev_noncomb_char (&act, in->buffer);
|
||||
}
|
||||
in->charpoint = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
forward_char (WInput *in)
|
||||
{
|
||||
if (in->buffer [in->point])
|
||||
in->point++;
|
||||
const char *act = in->buffer + str_offset_to_pos (in->buffer, in->point);
|
||||
if (act[0] != '\0') {
|
||||
in->point+= str_cnext_noncomb_char (&act);
|
||||
}
|
||||
in->charpoint = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
forward_word (WInput * in)
|
||||
{
|
||||
char *p = in->buffer + in->point;
|
||||
const char *p = in->buffer + str_offset_to_pos (in->buffer, in->point);
|
||||
|
||||
while (*p
|
||||
&& (isspace ((unsigned char) *p)
|
||||
|| ispunct ((unsigned char) *p)))
|
||||
p++;
|
||||
while (*p && isalnum ((unsigned char) *p))
|
||||
p++;
|
||||
in->point = p - in->buffer;
|
||||
while (p[0] != '\0' && (str_isspace (p) || str_ispunct (p))) {
|
||||
str_cnext_char (&p);
|
||||
in->point++;
|
||||
}
|
||||
while (p[0] != '\0' && !str_isspace (p) && !str_ispunct (p)) {
|
||||
str_cnext_char (&p);
|
||||
in->point++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
backward_word (WInput *in)
|
||||
{
|
||||
char *p = in->buffer + in->point;
|
||||
const char *p = in->buffer + str_offset_to_pos (in->buffer, in->point);
|
||||
|
||||
while (p - 1 > in->buffer - 1 && (isspace ((unsigned char) *(p - 1))
|
||||
|| ispunct ((unsigned char)
|
||||
*(p - 1))))
|
||||
while ((p != in->buffer) && (p[0] == '\0')) {
|
||||
p--;
|
||||
while (p - 1 > in->buffer - 1 && isalnum ((unsigned char) *(p - 1)))
|
||||
p--;
|
||||
in->point = p - in->buffer;
|
||||
in->point--;
|
||||
}
|
||||
|
||||
while ((p != in->buffer) && (str_isspace (p) || str_ispunct (p))) {
|
||||
str_cprev_char (&p);
|
||||
in->point--;
|
||||
}
|
||||
while ((p != in->buffer) && !str_isspace (p) && !str_ispunct (p)) {
|
||||
str_cprev_char (&p);
|
||||
in->point--;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1316,23 +1365,29 @@ key_ctrl_right (WInput *in)
|
||||
static void
|
||||
backward_delete (WInput *in)
|
||||
{
|
||||
int i;
|
||||
const char *act = in->buffer + str_offset_to_pos (in->buffer, in->point);
|
||||
int start;
|
||||
|
||||
if (!in->point)
|
||||
if (in->point == 0)
|
||||
return;
|
||||
for (i = in->point; in->buffer [i-1]; i++)
|
||||
in->buffer [i-1] = in->buffer [i];
|
||||
|
||||
start = in->point - str_cprev_noncomb_char (&act, in->buffer);
|
||||
move_buffer_backward(in, start, in->point);
|
||||
in->charpoint = 0;
|
||||
in->need_push = 1;
|
||||
in->point--;
|
||||
in->point = start;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_char (WInput *in)
|
||||
{
|
||||
int i;
|
||||
const char *act = in->buffer + str_offset_to_pos (in->buffer, in->point);
|
||||
int end = in->point;
|
||||
|
||||
for (i = in->point; in->buffer [i]; i++)
|
||||
in->buffer [i] = in->buffer [i+1];
|
||||
end+= str_cnext_noncomb_char (&act);
|
||||
|
||||
move_buffer_backward(in, in->point, end);
|
||||
in->charpoint = 0;
|
||||
in->need_push = 1;
|
||||
}
|
||||
|
||||
@ -1347,7 +1402,10 @@ copy_region (WInput *in, int x_first, int x_last)
|
||||
|
||||
g_free (kill_buffer);
|
||||
|
||||
kill_buffer = g_strndup(in->buffer+first,last-first);
|
||||
first = str_offset_to_pos (in->buffer, first);
|
||||
last = str_offset_to_pos (in->buffer, last);
|
||||
|
||||
kill_buffer = g_strndup(in->buffer + first, last - first);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1355,11 +1413,15 @@ delete_region (WInput *in, int x_first, int x_last)
|
||||
{
|
||||
int first = min (x_first, x_last);
|
||||
int last = max (x_first, x_last);
|
||||
size_t len = strlen (&in->buffer [last]) + 1;
|
||||
size_t len;
|
||||
|
||||
in->point = first;
|
||||
in->mark = first;
|
||||
memmove (&in->buffer [first], &in->buffer [last], len);
|
||||
last = str_offset_to_pos (in->buffer, last);
|
||||
first = str_offset_to_pos (in->buffer, first);
|
||||
len = strlen (&in->buffer[last]) + 1;
|
||||
memmove (&in->buffer[first], &in->buffer[last], len);
|
||||
in->charpoint = 0;
|
||||
in->need_push = 1;
|
||||
}
|
||||
|
||||
@ -1376,6 +1438,8 @@ kill_word (WInput *in)
|
||||
copy_region (in, old_point, new_point);
|
||||
delete_region (in, old_point, new_point);
|
||||
in->need_push = 1;
|
||||
in->charpoint = 0;
|
||||
in->charpoint = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1419,16 +1483,20 @@ yank (WInput *in)
|
||||
|
||||
if (!kill_buffer)
|
||||
return;
|
||||
in->charpoint = 0;
|
||||
for (p = kill_buffer; *p; p++)
|
||||
insert_char (in, *p);
|
||||
in->charpoint = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
kill_line (WInput *in)
|
||||
{
|
||||
int chp = str_offset_to_pos (in->buffer, in->point);
|
||||
g_free (kill_buffer);
|
||||
kill_buffer = g_strdup (&in->buffer [in->point]);
|
||||
in->buffer [in->point] = 0;
|
||||
kill_buffer = g_strdup (&in->buffer[chp]);
|
||||
in->buffer[chp] = '\0';
|
||||
in->charpoint = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1437,10 +1505,11 @@ assign_text (WInput *in, const char *text)
|
||||
free_completions (in);
|
||||
g_free (in->buffer);
|
||||
in->buffer = g_strdup (text); /* was in->buffer->text */
|
||||
in->current_max_len = strlen (in->buffer) + 1;
|
||||
in->point = strlen (in->buffer);
|
||||
in->current_max_size = strlen (in->buffer) + 1;
|
||||
in->point = str_length (in->buffer);
|
||||
in->mark = 0;
|
||||
in->need_push = 1;
|
||||
in->charpoint = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1564,9 +1633,10 @@ is_in_input_map (WInput *in, int c_code)
|
||||
static void
|
||||
port_region_marked_for_delete (WInput *in)
|
||||
{
|
||||
*in->buffer = 0;
|
||||
in->buffer[0] = '\0';
|
||||
in->point = 0;
|
||||
in->first = 0;
|
||||
in->charpoint = 0;
|
||||
}
|
||||
|
||||
cb_ret_t
|
||||
@ -1595,7 +1665,7 @@ handle_char (WInput *in, int c_code)
|
||||
}
|
||||
}
|
||||
if (!input_map [i].fn){
|
||||
if (c_code > 255 || !is_printable (c_code))
|
||||
if (c_code > 255)
|
||||
return MSG_NOT_HANDLED;
|
||||
if (in->first){
|
||||
port_region_marked_for_delete (in);
|
||||
@ -1623,11 +1693,14 @@ stuff (WInput *in, const char *text, int insert_extra_space)
|
||||
void
|
||||
input_set_point (WInput *in, int pos)
|
||||
{
|
||||
if (pos > in->current_max_len)
|
||||
pos = in->current_max_len;
|
||||
int max_pos = str_length (in->buffer);
|
||||
|
||||
if (pos > max_pos)
|
||||
pos = max_pos;
|
||||
if (pos != in->point)
|
||||
free_completions (in);
|
||||
in->point = pos;
|
||||
in->charpoint = 0;
|
||||
update_input (in, 1);
|
||||
}
|
||||
|
||||
@ -1668,7 +1741,8 @@ input_callback (Widget *w, widget_msg_t msg, int parm)
|
||||
return MSG_HANDLED;
|
||||
|
||||
case WIDGET_CURSOR:
|
||||
widget_move (&in->widget, 0, in->point - in->first_shown);
|
||||
widget_move (&in->widget, 0, str_term_width2 (in->buffer, in->point)
|
||||
- in->term_first_shown);
|
||||
return MSG_HANDLED;
|
||||
|
||||
case WIDGET_DESTROY:
|
||||
@ -1688,15 +1762,17 @@ input_event (Gpm_Event * event, void *data)
|
||||
if (event->type & (GPM_DOWN | GPM_DRAG)) {
|
||||
dlg_select_widget (in);
|
||||
|
||||
if (event->x >= in->field_len - HISTORY_BUTTON_WIDTH + 1
|
||||
if (event->x >= in->field_width - HISTORY_BUTTON_WIDTH + 1
|
||||
&& should_show_history_button (in)) {
|
||||
do_show_hist (in);
|
||||
} else {
|
||||
in->point = strlen (in->buffer);
|
||||
if (event->x - in->first_shown - 1 < in->point)
|
||||
in->point = event->x - in->first_shown - 1;
|
||||
if (in->point < 0)
|
||||
in->point = 0;
|
||||
in->point = str_length (in->buffer);
|
||||
if (event->x + in->term_first_shown - 1 <
|
||||
str_term_width1 (in->buffer))
|
||||
|
||||
in->point = str_column_to_pos (in->buffer, event->x
|
||||
+ in->term_first_shown - 1);
|
||||
|
||||
}
|
||||
update_input (in, 1);
|
||||
}
|
||||
@ -1704,13 +1780,13 @@ input_event (Gpm_Event * event, void *data)
|
||||
}
|
||||
|
||||
WInput *
|
||||
input_new (int y, int x, int color, int len, const char *def_text,
|
||||
input_new (int y, int x, int color, int width, const char *def_text,
|
||||
const char *histname)
|
||||
{
|
||||
WInput *in = g_new (WInput, 1);
|
||||
int initial_buffer_len;
|
||||
|
||||
init_widget (&in->widget, y, x, 1, len, input_callback, input_event);
|
||||
init_widget (&in->widget, y, x, 1, width, input_callback, input_event);
|
||||
|
||||
/* history setup */
|
||||
in->history = NULL;
|
||||
@ -1722,7 +1798,7 @@ input_new (int y, int x, int color, int len, const char *def_text,
|
||||
}
|
||||
}
|
||||
|
||||
if (!def_text)
|
||||
if (def_text == NULL)
|
||||
def_text = "";
|
||||
|
||||
if (def_text == INPUT_LAST_TEXT) {
|
||||
@ -1731,29 +1807,29 @@ input_new (int y, int x, int color, int len, const char *def_text,
|
||||
if (in->history->data)
|
||||
def_text = (char *) in->history->data;
|
||||
}
|
||||
initial_buffer_len = 1 + max ((size_t) len, strlen (def_text));
|
||||
initial_buffer_len = 1 + max ((size_t) width, strlen (def_text));
|
||||
in->widget.options |= W_IS_INPUT;
|
||||
in->completions = NULL;
|
||||
in->completion_flags =
|
||||
INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_HOSTNAMES |
|
||||
INPUT_COMPLETE_VARIABLES | INPUT_COMPLETE_USERNAMES;
|
||||
in->current_max_len = initial_buffer_len;
|
||||
in->buffer = g_malloc (initial_buffer_len);
|
||||
in->current_max_size = initial_buffer_len;
|
||||
in->buffer = g_new (char, initial_buffer_len);
|
||||
in->color = color;
|
||||
in->field_len = len;
|
||||
in->field_width = width;
|
||||
in->first = 1;
|
||||
in->first_shown = 0;
|
||||
in->term_first_shown = 0;
|
||||
in->disable_update = 0;
|
||||
in->mark = 0;
|
||||
in->need_push = 1;
|
||||
in->is_password = 0;
|
||||
|
||||
strcpy (in->buffer, def_text);
|
||||
in->point = strlen (in->buffer);
|
||||
in->point = str_length (in->buffer);
|
||||
in->charpoint = 0;
|
||||
return in;
|
||||
}
|
||||
|
||||
|
||||
/* Listbox widget */
|
||||
|
||||
/* Should draw the scrollbar, but currently draws only
|
||||
|
16
src/widget.h
16
src/widget.h
@ -74,11 +74,11 @@ char *show_hist (GList *history, int widget_y, int widget_x);
|
||||
|
||||
typedef struct {
|
||||
Widget widget;
|
||||
int point; /* cursor position in the input line */
|
||||
int mark; /* The mark position */
|
||||
int first_shown; /* Index of the first shown character */
|
||||
int current_max_len; /* Maximum length of input line */
|
||||
int field_len; /* Length of the editing field */
|
||||
int point; /* cursor position in the input line in characters */
|
||||
int mark; /* The mark position in characters */
|
||||
int term_first_shown; /* column of the first shown character */
|
||||
size_t current_max_size; /* Maximum length of input line (bytes) */
|
||||
int field_width; /* width of the editing field */
|
||||
int color; /* color used */
|
||||
int first; /* Is first keystroke? */
|
||||
int disable_update; /* Do we want to skip updates? */
|
||||
@ -89,6 +89,8 @@ typedef struct {
|
||||
char **completions; /* Possible completions array */
|
||||
int completion_flags; /* INPUT_COMPLETE* bitwise flags(complete.h) */
|
||||
char *history_name; /* name of history for loading and saving */
|
||||
char charbuf[MB_LEN_MAX]; /* buffer for multibytes characters */
|
||||
size_t charpoint; /* point to end of mulibyte sequence in charbuf */
|
||||
} WInput;
|
||||
|
||||
/* For history load-save functions */
|
||||
@ -144,14 +146,14 @@ WButton *button_new (int y, int x, int action, int flags, const char *text,
|
||||
bcback callback);
|
||||
WRadio *radio_new (int y, int x, int count, const char **text);
|
||||
WCheck *check_new (int y, int x, int state, const char *text);
|
||||
WInput *input_new (int y, int x, int color, int len, const char *text, const char *histname);
|
||||
WInput *input_new (int y, int x, int color, int width, const char *text, const char *histname);
|
||||
WLabel *label_new (int y, int x, const char *text);
|
||||
WGauge *gauge_new (int y, int x, int shown, int max, int current);
|
||||
WListbox *listbox_new (int x, int y, int width, int height, lcback callback);
|
||||
WGroupbox *groupbox_new (int x, int y, int width, int height, const char *title);
|
||||
|
||||
/* Input lines */
|
||||
void winput_set_origin (WInput *i, int x, int field_len);
|
||||
void winput_set_origin (WInput *i, int x, int field_width);
|
||||
cb_ret_t handle_char (WInput *in, int c_code);
|
||||
int is_in_input_map (WInput *in, int c_code);
|
||||
void update_input (WInput *in, int clear_first);
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user