fix bind command arg completion crash.
add modifier key combos to bind arg completion. don't force completion quite so aggressively. completion is now more consistent with cl_chatmode 0. alt key allows moving the cursor into console links to edit them (instead of treating them as immutable blobs on the input line). git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5245 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
8df89fc186
commit
2769443729
4 changed files with 125 additions and 29 deletions
|
@ -1292,6 +1292,34 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y,
|
||||||
endmtext[-1] = CON_WHITEMASK | '+' | CON_NONCLEARBG;
|
endmtext[-1] = CON_WHITEMASK | '+' | CON_NONCLEARBG;
|
||||||
endmtext[1] = 0;
|
endmtext[1] = 0;
|
||||||
|
|
||||||
|
if ((*cursor & CON_HIDDEN) && cursor[0] != (CON_HIDDEN|'^') && cursor[1] != CON_LINKSTART)
|
||||||
|
{ //if we're in the middle of a link (but not at the very first char - to make life prettier) then reveal the hidden text so that you can actually see what you're editing.
|
||||||
|
for (i = cursor-textstart; textstart[i]; i++)
|
||||||
|
{
|
||||||
|
if (textstart[i] == CON_LINKSTART)
|
||||||
|
break;
|
||||||
|
if (textstart[i] == CON_LINKEND)
|
||||||
|
{
|
||||||
|
textstart[i] &= ~CON_HIDDEN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
textstart[i] &= ~CON_HIDDEN;
|
||||||
|
}
|
||||||
|
for (i = cursor-textstart; i>=0; i--)
|
||||||
|
{
|
||||||
|
if (textstart[i] == CON_LINKEND)
|
||||||
|
break;
|
||||||
|
if (textstart[i] == CON_LINKSTART)
|
||||||
|
{
|
||||||
|
textstart[i] &= ~CON_HIDDEN;
|
||||||
|
if (--i >= 0) //make the ^ of the ^[ shown too.
|
||||||
|
textstart[i] &= ~CON_HIDDEN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
textstart[i] &= ~CON_HIDDEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
x = left;
|
x = left;
|
||||||
|
|
||||||
|
@ -1414,6 +1442,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y,
|
||||||
{
|
{
|
||||||
s = (conchar_t*)(con->completionline+1);
|
s = (conchar_t*)(con->completionline+1);
|
||||||
|
|
||||||
|
//note: if cl_chatmode is 0, then we shouldn't show the leading /, however that is how the console link stuff recognises it as command text, so we always display it.
|
||||||
cmd = c->completions[i].text;
|
cmd = c->completions[i].text;
|
||||||
// desc = c->completions[i].desc;
|
// desc = c->completions[i].desc;
|
||||||
// if (desc)
|
// if (desc)
|
||||||
|
|
|
@ -381,7 +381,8 @@ void Key_UpdateCompletionDesc(void)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Con_Footerf(NULL, false, "");
|
Con_Footerf(NULL, false, "");
|
||||||
con_commandmatch = 1;
|
if (con_commandmatch)
|
||||||
|
con_commandmatch = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,7 +424,8 @@ void CompleteCommand (qboolean force)
|
||||||
|
|
||||||
//complete to that (maybe partial) cmd.
|
//complete to that (maybe partial) cmd.
|
||||||
Key_ClearTyping();
|
Key_ClearTyping();
|
||||||
Key_ConsoleInsert("/");
|
if (cl_chatmode.ival)
|
||||||
|
Key_ConsoleInsert("/");
|
||||||
Key_ConsoleInsert(cmd);
|
Key_ConsoleInsert(cmd);
|
||||||
s = key_lines[edit_line];
|
s = key_lines[edit_line];
|
||||||
if (*s == '/')
|
if (*s == '/')
|
||||||
|
@ -454,7 +456,8 @@ void CompleteCommand (qboolean force)
|
||||||
if (i != 1 || strcmp(key_lines[edit_line]+i, cmd))
|
if (i != 1 || strcmp(key_lines[edit_line]+i, cmd))
|
||||||
{ //if successful, use that instead.
|
{ //if successful, use that instead.
|
||||||
Key_ClearTyping();
|
Key_ClearTyping();
|
||||||
Key_ConsoleInsert("/");
|
if (cl_chatmode.ival)
|
||||||
|
Key_ConsoleInsert("/");
|
||||||
Key_ConsoleInsert(cmd);
|
Key_ConsoleInsert(cmd);
|
||||||
|
|
||||||
s = key_lines[edit_line]; //readjust to cope with the insertion of a /
|
s = key_lines[edit_line]; //readjust to cope with the insertion of a /
|
||||||
|
@ -504,7 +507,8 @@ int Con_ExecuteLine(console_t *con, char *line)
|
||||||
line = deutf8;
|
line = deutf8;
|
||||||
}
|
}
|
||||||
|
|
||||||
con_commandmatch=1;
|
if (con_commandmatch)
|
||||||
|
con_commandmatch=1;
|
||||||
Con_Footerf(con, false, "");
|
Con_Footerf(con, false, "");
|
||||||
|
|
||||||
if (cls.state >= ca_connected && cl_chatmode.value == 2)
|
if (cls.state >= ca_connected && cl_chatmode.value == 2)
|
||||||
|
@ -981,12 +985,17 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info)
|
||||||
text+=2;
|
text+=2;
|
||||||
if (*text == '/')
|
if (*text == '/')
|
||||||
{
|
{
|
||||||
int tlen = info - text;
|
int tlen;
|
||||||
|
if (!cl_chatmode.ival)
|
||||||
|
text++; //NQ should generally not bother with the / in commands.
|
||||||
|
tlen = info - text;
|
||||||
Z_Free(key_lines[edit_line]);
|
Z_Free(key_lines[edit_line]);
|
||||||
key_lines[edit_line] = BZ_Malloc(tlen + 1);
|
key_lines[edit_line] = BZ_Malloc(tlen + 1);
|
||||||
memcpy(key_lines[edit_line], text, tlen);
|
memcpy(key_lines[edit_line], text, tlen);
|
||||||
key_lines[edit_line][tlen] = 0;
|
key_lines[edit_line][tlen] = 0;
|
||||||
key_linepos = strlen(key_lines[edit_line]);
|
key_linepos = strlen(key_lines[edit_line]);
|
||||||
|
|
||||||
|
Key_UpdateCompletionDesc();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1129,7 +1138,7 @@ static qboolean utf_specialchevron(unsigned char *start, unsigned char *chev)
|
||||||
return count&1;
|
return count&1;
|
||||||
}
|
}
|
||||||
//move the cursor one char to the left. cursor must be within the 'start' string.
|
//move the cursor one char to the left. cursor must be within the 'start' string.
|
||||||
static unsigned char *utf_left(unsigned char *start, unsigned char *cursor)
|
static unsigned char *utf_left(unsigned char *start, unsigned char *cursor, qboolean skiplink)
|
||||||
{
|
{
|
||||||
if (cursor == start)
|
if (cursor == start)
|
||||||
return cursor;
|
return cursor;
|
||||||
|
@ -1143,7 +1152,7 @@ static unsigned char *utf_left(unsigned char *start, unsigned char *cursor)
|
||||||
cursor--;
|
cursor--;
|
||||||
|
|
||||||
//FIXME: should verify that the ^ isn't doubled.
|
//FIXME: should verify that the ^ isn't doubled.
|
||||||
if (*cursor == ']' && cursor > start && utf_specialchevron(start, cursor-1))
|
if (*cursor == ']' && cursor > start && skiplink && utf_specialchevron(start, cursor-1))
|
||||||
{
|
{
|
||||||
//just stepped onto a link
|
//just stepped onto a link
|
||||||
unsigned char *linkstart;
|
unsigned char *linkstart;
|
||||||
|
@ -1161,10 +1170,10 @@ static unsigned char *utf_left(unsigned char *start, unsigned char *cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
//move the cursor one char to the right.
|
//move the cursor one char to the right.
|
||||||
static unsigned char *utf_right(unsigned char *start, unsigned char *cursor)
|
static unsigned char *utf_right(unsigned char *start, unsigned char *cursor, qboolean skiplink)
|
||||||
{
|
{
|
||||||
//FIXME: should make sure this is not doubled.
|
//FIXME: should make sure this is not doubled.
|
||||||
if (utf_specialchevron(start, cursor) && cursor[1] == '[')
|
if (utf_specialchevron(start, cursor) && cursor[1] == '[' && skiplink)
|
||||||
{
|
{
|
||||||
//just stepped over a link
|
//just stepped over a link
|
||||||
char *linkend;
|
char *linkend;
|
||||||
|
@ -1240,6 +1249,7 @@ void Key_EntryInsert(unsigned char **line, int *linepos, char *instext)
|
||||||
|
|
||||||
qboolean Key_EntryLine(unsigned char **line, int lineoffset, int *linepos, int key, unsigned int unicode)
|
qboolean Key_EntryLine(unsigned char **line, int lineoffset, int *linepos, int key, unsigned int unicode)
|
||||||
{
|
{
|
||||||
|
qboolean alt = keydown[K_LALT] || keydown[K_RALT];
|
||||||
qboolean ctrl = keydown[K_LCTRL] || keydown[K_RCTRL];
|
qboolean ctrl = keydown[K_LCTRL] || keydown[K_RCTRL];
|
||||||
qboolean shift = keydown[K_LSHIFT] || keydown[K_RSHIFT];
|
qboolean shift = keydown[K_LSHIFT] || keydown[K_RSHIFT];
|
||||||
char utf8[8];
|
char utf8[8];
|
||||||
|
@ -1250,28 +1260,28 @@ qboolean Key_EntryLine(unsigned char **line, int lineoffset, int *linepos, int k
|
||||||
{
|
{
|
||||||
//ignore whitespace if we're at the end of the word
|
//ignore whitespace if we're at the end of the word
|
||||||
while (*linepos > 0 && (*line)[*linepos-1] == ' ')
|
while (*linepos > 0 && (*line)[*linepos-1] == ' ')
|
||||||
*linepos = utf_left((*line)+lineoffset, (*line) + *linepos) - (*line);
|
*linepos = utf_left((*line)+lineoffset, (*line) + *linepos, !alt) - (*line);
|
||||||
//keep skipping until we find the start of that word
|
//keep skipping until we find the start of that word
|
||||||
while (ctrl && *linepos > lineoffset && (*line)[*linepos-1] != ' ')
|
while (ctrl && *linepos > lineoffset && (*line)[*linepos-1] != ' ')
|
||||||
*linepos = utf_left((*line)+lineoffset, (*line) + *linepos) - (*line);
|
*linepos = utf_left((*line)+lineoffset, (*line) + *linepos, !alt) - (*line);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*linepos = utf_left((*line)+lineoffset, (*line) + *linepos) - (*line);
|
*linepos = utf_left((*line)+lineoffset, (*line) + *linepos, !alt) - (*line);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (key == K_RIGHTARROW || key == K_KP_RIGHTARROW)
|
if (key == K_RIGHTARROW || key == K_KP_RIGHTARROW)
|
||||||
{
|
{
|
||||||
if ((*line)[*linepos])
|
if ((*line)[*linepos])
|
||||||
{
|
{
|
||||||
*linepos = utf_right((*line)+lineoffset, (*line) + *linepos) - (*line);
|
*linepos = utf_right((*line)+lineoffset, (*line) + *linepos, !alt) - (*line);
|
||||||
if (ctrl)
|
if (ctrl)
|
||||||
{
|
{
|
||||||
//skip over the word
|
//skip over the word
|
||||||
while ((*line)[*linepos] && (*line)[*linepos] != ' ')
|
while ((*line)[*linepos] && (*line)[*linepos] != ' ')
|
||||||
*linepos = utf_right((*line)+lineoffset, (*line) + *linepos) - (*line);
|
*linepos = utf_right((*line)+lineoffset, (*line) + *linepos, !alt) - (*line);
|
||||||
//as well as any trailing whitespace
|
//as well as any trailing whitespace
|
||||||
while ((*line)[*linepos] == ' ')
|
while ((*line)[*linepos] == ' ')
|
||||||
*linepos = utf_right((*line)+lineoffset, (*line) + *linepos) - (*line);
|
*linepos = utf_right((*line)+lineoffset, (*line) + *linepos, !alt) - (*line);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1283,7 +1293,7 @@ qboolean Key_EntryLine(unsigned char **line, int lineoffset, int *linepos, int k
|
||||||
{
|
{
|
||||||
if ((*line)[*linepos])
|
if ((*line)[*linepos])
|
||||||
{
|
{
|
||||||
int charlen = utf_right((*line)+lineoffset, (*line) + *linepos) - ((*line) + *linepos);
|
int charlen = utf_right((*line)+lineoffset, (*line) + *linepos, !alt) - ((*line) + *linepos);
|
||||||
memmove((*line)+*linepos, (*line)+*linepos+charlen, strlen((*line)+*linepos+charlen)+1);
|
memmove((*line)+*linepos, (*line)+*linepos+charlen, strlen((*line)+*linepos+charlen)+1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1295,7 +1305,7 @@ qboolean Key_EntryLine(unsigned char **line, int lineoffset, int *linepos, int k
|
||||||
{
|
{
|
||||||
if (*linepos > lineoffset)
|
if (*linepos > lineoffset)
|
||||||
{
|
{
|
||||||
int charlen = ((*line)+*linepos) - utf_left((*line)+lineoffset, (*line) + *linepos);
|
int charlen = ((*line)+*linepos) - utf_left((*line)+lineoffset, (*line) + *linepos, !alt);
|
||||||
memmove((*line)+*linepos-charlen, (*line)+*linepos, strlen((*line)+*linepos)+1);
|
memmove((*line)+*linepos-charlen, (*line)+*linepos, strlen((*line)+*linepos)+1);
|
||||||
*linepos -= charlen;
|
*linepos -= charlen;
|
||||||
}
|
}
|
||||||
|
@ -1303,7 +1313,7 @@ qboolean Key_EntryLine(unsigned char **line, int lineoffset, int *linepos, int k
|
||||||
if (con_commandmatch)
|
if (con_commandmatch)
|
||||||
{
|
{
|
||||||
Con_Footerf(NULL, false, "");
|
Con_Footerf(NULL, false, "");
|
||||||
con_commandmatch = 1;
|
con_commandmatch = (**line?1:0);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1669,8 +1679,6 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key)
|
||||||
CompleteCommand (ctrl);
|
CompleteCommand (ctrl);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (key != K_CTRL && key != K_SHIFT && con_commandmatch)
|
|
||||||
con_commandmatch=1;
|
|
||||||
|
|
||||||
if (key == K_UPARROW || key == K_KP_UPARROW || key == K_GP_DPAD_UP)
|
if (key == K_UPARROW || key == K_KP_UPARROW || key == K_GP_DPAD_UP)
|
||||||
{
|
{
|
||||||
|
@ -1685,8 +1693,7 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key)
|
||||||
Q_strcpy(key_lines[edit_line], key_lines[history_line]);
|
Q_strcpy(key_lines[edit_line], key_lines[history_line]);
|
||||||
key_linepos = Q_strlen(key_lines[edit_line]);
|
key_linepos = Q_strlen(key_lines[edit_line]);
|
||||||
|
|
||||||
if (!key_lines[edit_line][0])
|
con_commandmatch = 0;
|
||||||
con_commandmatch = 0;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1724,6 +1731,8 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key)
|
||||||
if (rkey != '`' || key_linepos==0)
|
if (rkey != '`' || key_linepos==0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (con_commandmatch)
|
||||||
|
con_commandmatch = 1;
|
||||||
Key_EntryLine(&key_lines[edit_line], 0, &key_linepos, key, unicode);
|
Key_EntryLine(&key_lines[edit_line], 0, &key_linepos, key, unicode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2035,13 +2044,67 @@ void Key_Unbindall_f (void)
|
||||||
|
|
||||||
void Key_Bind_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx)
|
void Key_Bind_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx)
|
||||||
{
|
{
|
||||||
|
int key, mf;
|
||||||
keyname_t *kn;
|
keyname_t *kn;
|
||||||
size_t len = strlen(partial);
|
const char *n, *m;
|
||||||
//FIXME: shift, ctrl, alt prefixes (+combos)
|
size_t len = strlen(partial), l;
|
||||||
for (kn=keynames ; kn->name ; kn++)
|
struct
|
||||||
{
|
{
|
||||||
if (!Q_strncasecmp(partial,kn->name, len))
|
const char *prefix;
|
||||||
ctx->cb(kn->name, NULL, NULL, ctx);
|
int mods;
|
||||||
|
} mtab[] =
|
||||||
|
{
|
||||||
|
{"",0},
|
||||||
|
|
||||||
|
{"CTRL+ALT+SHIFT+",KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT},
|
||||||
|
{"ALT+CTRL+SHIFT+",KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT},
|
||||||
|
{"SHIFT+CTRL+ALT+",KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT},
|
||||||
|
{"SHIFT+ALT+CTRL+",KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT},
|
||||||
|
{"CTRL+SHIFT+ALT+",KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT},
|
||||||
|
{"ALT+SHIFT+CTRL+",KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT},
|
||||||
|
|
||||||
|
{"CTRL+ALT+",KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT},
|
||||||
|
{"ALT+CTRL+",KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT},
|
||||||
|
{"SHIFT+ALT+",KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT},
|
||||||
|
{"ALT+SHIFT+",KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT},
|
||||||
|
{"CTRL+SHIFT+",KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT},
|
||||||
|
{"SHIFT+CTRL+",KEY_MODIFIER_CTRL|KEY_MODIFIER_ALT|KEY_MODIFIER_SHIFT},
|
||||||
|
|
||||||
|
{"CTRL+",KEY_MODIFIER_CTRL},
|
||||||
|
{"ALT+",KEY_MODIFIER_ALT},
|
||||||
|
{"SHIFT+",KEY_MODIFIER_SHIFT},
|
||||||
|
};
|
||||||
|
for (l = 0; l < countof(mtab); l++)
|
||||||
|
{
|
||||||
|
m = mtab[l].prefix;
|
||||||
|
mf = strlen(m);
|
||||||
|
mf = min(mf, len);
|
||||||
|
if (Q_strncasecmp(partial, m, mf))
|
||||||
|
continue;
|
||||||
|
mf = mtab[l].mods;
|
||||||
|
|
||||||
|
for (kn=keynames ; kn->name ; kn++)
|
||||||
|
{
|
||||||
|
//don't suggest shift+shift, because that would be weird.
|
||||||
|
if ((mf & KEY_MODIFIER_CTRL) && (kn->keynum == K_LCTRL || kn->keynum == K_RCTRL))
|
||||||
|
continue;
|
||||||
|
if ((mf & KEY_MODIFIER_ALT) && (kn->keynum == K_LALT || kn->keynum == K_RALT))
|
||||||
|
continue;
|
||||||
|
if ((mf & KEY_MODIFIER_SHIFT) && (kn->keynum == K_LSHIFT || kn->keynum == K_RSHIFT))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
n = va("%s%s", m, kn->name);
|
||||||
|
if (!Q_strncasecmp(partial,n, len))
|
||||||
|
ctx->cb(n, NULL, NULL, ctx);
|
||||||
|
}
|
||||||
|
for (key = 32+1; key < 127; key++)
|
||||||
|
{
|
||||||
|
if (key >= 'a' && key <= 'z')
|
||||||
|
continue;
|
||||||
|
n = va("%s%c", m, key);
|
||||||
|
if (!Q_strncasecmp(partial,n, len))
|
||||||
|
ctx->cb(n, NULL, NULL, ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -3499,5 +3499,9 @@ void CL_Connect_c(int argn, const char *partial, struct xcommandargcompletioncb_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
void CL_Connect_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx)
|
||||||
|
{
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -2280,7 +2280,7 @@ void Cmd_Complete_CheckArg(const char *value, const char *desc, const char *repl
|
||||||
res->completions[res->num].text_alloced = true;
|
res->completions[res->num].text_alloced = true;
|
||||||
res->completions[res->num].text = text;
|
res->completions[res->num].text = text;
|
||||||
res->completions[res->num].desc_alloced = true;
|
res->completions[res->num].desc_alloced = true;
|
||||||
res->completions[res->num].desc = Z_StrDup(desc);
|
res->completions[res->num].desc = desc?Z_StrDup(desc):NULL;
|
||||||
res->completions[res->num].repl = repl;
|
res->completions[res->num].repl = repl;
|
||||||
res->num++;
|
res->num++;
|
||||||
}
|
}
|
||||||
|
@ -2396,7 +2396,7 @@ cmd_completion_t *Cmd_Complete(const char *partial, qboolean caseinsens)
|
||||||
else
|
else
|
||||||
sp = NULL;
|
sp = NULL;
|
||||||
|
|
||||||
if (len)
|
// if (len)
|
||||||
{
|
{
|
||||||
if (caseinsens)
|
if (caseinsens)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue