mirror of
https://github.com/Tha14/toxic.git
synced 2024-11-26 15:03:27 +01:00
auto-completion for paths when sending file & improved auto-complete algorithm to do partial matches
This commit is contained in:
parent
e61d070def
commit
ea3fcd5b79
@ -22,7 +22,7 @@ CFLAGS += $(USER_CFLAGS)
|
|||||||
LDFLAGS = $(USER_LDFLAGS)
|
LDFLAGS = $(USER_LDFLAGS)
|
||||||
|
|
||||||
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o
|
OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o
|
||||||
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o
|
OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o
|
||||||
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o
|
OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o
|
||||||
|
|
||||||
# Variables for audio support
|
# Variables for audio support
|
||||||
|
251
src/autocomplete.c
Normal file
251
src/autocomplete.c
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
/* autocomplete.c
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This file is part of Toxic.
|
||||||
|
*
|
||||||
|
* Toxic is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Toxic is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/dir.h>
|
||||||
|
#else
|
||||||
|
#include <dirent.h>
|
||||||
|
#endif /* ifdef __APPLE__ */
|
||||||
|
|
||||||
|
#include "windows.h"
|
||||||
|
#include "toxic.h"
|
||||||
|
#include "misc_tools.h"
|
||||||
|
#include "line_info.h"
|
||||||
|
#include "execute.h"
|
||||||
|
|
||||||
|
/* puts match in match buffer. if more than one match, add first n chars that are identical.
|
||||||
|
e.g. if matches contains: [foo, foobar, foe] we put fo in matches. */
|
||||||
|
static void get_str_match(char *match, char (*matches)[MAX_STR_SIZE], int n)
|
||||||
|
{
|
||||||
|
if (n == 1) {
|
||||||
|
strcpy(match, matches[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int shortest = MAX_STR_SIZE;
|
||||||
|
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
int m_len = strlen(matches[i]);
|
||||||
|
|
||||||
|
if (m_len < shortest)
|
||||||
|
shortest = m_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < shortest; ++i) {
|
||||||
|
char ch = matches[0][i];
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (j = 0; j < n; ++j) {
|
||||||
|
if (matches[j][i] != ch) {
|
||||||
|
strcpy(match, matches[0]);
|
||||||
|
match[i] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(match, matches[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* looks for the first instance in list that begins with the last entered word in line according to pos,
|
||||||
|
then fills line with the complete word. e.g. "Hello jo" would complete the line
|
||||||
|
with "Hello john". Works slightly differently for directory paths with the same results.
|
||||||
|
|
||||||
|
list is a pointer to the list of strings being compared, n_items is the number of items
|
||||||
|
in the list, and size is the size of each item in the list.
|
||||||
|
|
||||||
|
Returns the difference between the old len and new len of line on success, -1 if error */
|
||||||
|
int complete_line(ChatContext *ctx, const void *list, int n_items, int size)
|
||||||
|
{
|
||||||
|
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
const char *L = (char *) list;
|
||||||
|
|
||||||
|
bool dir_search = false;
|
||||||
|
const char *endchrs = " ";
|
||||||
|
char ubuf[MAX_STR_SIZE];
|
||||||
|
|
||||||
|
/* work with multibyte string copy of buf for simplicity */
|
||||||
|
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* isolate substring from space behind pos to pos */
|
||||||
|
char tmp[MAX_STR_SIZE];
|
||||||
|
snprintf(tmp, sizeof(tmp), "%s", ubuf);
|
||||||
|
tmp[ctx->pos] = '\0';
|
||||||
|
|
||||||
|
const char *s = strrchr(tmp, ' ');
|
||||||
|
char *sub = malloc(strlen(ubuf) + 1);
|
||||||
|
|
||||||
|
if (sub == NULL)
|
||||||
|
exit_toxic_err("failed in complete_line", FATALERR_MEMORY);
|
||||||
|
|
||||||
|
if (!s) {
|
||||||
|
strcpy(sub, tmp);
|
||||||
|
|
||||||
|
if (sub[0] != '/')
|
||||||
|
endchrs = ": ";
|
||||||
|
} else {
|
||||||
|
strcpy(sub, &s[1]);
|
||||||
|
|
||||||
|
if (strncmp(ubuf, "/sendfile", strlen("/sendfile")) == 0) {
|
||||||
|
dir_search = true;
|
||||||
|
int sub_len = strlen(sub);
|
||||||
|
int si = char_rfind(sub, '/', sub_len);
|
||||||
|
memmove(sub, &sub[si + 1], sub_len - si);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string_is_empty(sub)) {
|
||||||
|
free(sub);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int s_len = strlen(sub);
|
||||||
|
const char *str;
|
||||||
|
int n_matches = 0;
|
||||||
|
char matches[n_items][MAX_STR_SIZE];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
/* put all list matches in matches array */
|
||||||
|
for (i = 0; i < n_items; ++i) {
|
||||||
|
str = &L[i * size];
|
||||||
|
|
||||||
|
if (strncasecmp(str, sub, s_len) == 0)
|
||||||
|
strcpy(matches[n_matches++], str);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(sub);
|
||||||
|
|
||||||
|
if (!n_matches)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char match[size];
|
||||||
|
get_str_match(match, matches, n_matches);
|
||||||
|
|
||||||
|
if (dir_search) {
|
||||||
|
if (n_matches == 1)
|
||||||
|
endchrs = char_rfind(match, '.', strlen(match)) ? "\"" : "/";
|
||||||
|
else
|
||||||
|
endchrs = "";
|
||||||
|
} else if (n_matches > 1) {
|
||||||
|
endchrs = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* put match in correct spot in buf and append endchars */
|
||||||
|
int n_endchrs = strlen(endchrs);
|
||||||
|
int m_len = strlen(match);
|
||||||
|
int strt = ctx->pos - s_len;
|
||||||
|
int diff = m_len - s_len + n_endchrs;
|
||||||
|
|
||||||
|
if (ctx->len + diff > MAX_STR_SIZE)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char tmpend[MAX_STR_SIZE];
|
||||||
|
strcpy(tmpend, &ubuf[ctx->pos]);
|
||||||
|
strcpy(&ubuf[strt], match);
|
||||||
|
strcpy(&ubuf[strt + m_len], endchrs);
|
||||||
|
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
|
||||||
|
|
||||||
|
/* convert to widechar and copy back to original buf */
|
||||||
|
wchar_t newbuf[MAX_STR_SIZE];
|
||||||
|
|
||||||
|
if (mbs_to_wcs_buf(newbuf, ubuf, MAX_STR_SIZE) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
wcscpy(ctx->line, newbuf);
|
||||||
|
|
||||||
|
ctx->len += diff;
|
||||||
|
ctx->pos += diff;
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* matches /sendfile "<incomplete-dir>" line to matching directories.
|
||||||
|
|
||||||
|
if only one match, auto-complete line and return diff between old len and new len.
|
||||||
|
return 0 if > 1 match and print out all the matches
|
||||||
|
return -1 if no matches */
|
||||||
|
|
||||||
|
#define MAX_DIRS 256
|
||||||
|
|
||||||
|
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line)
|
||||||
|
{
|
||||||
|
char b_path[MAX_STR_SIZE];
|
||||||
|
char b_name[MAX_STR_SIZE];
|
||||||
|
|
||||||
|
if (wcs_to_mbs_buf(b_path, line, sizeof(b_path)) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int si = char_rfind(b_path, '/', strlen(b_path));
|
||||||
|
|
||||||
|
if (!b_path[0]) { /* list everything in pwd */
|
||||||
|
strcpy(b_path, ".");
|
||||||
|
} else if (!si && b_path[0] != '/') { /* look for matches in pwd */
|
||||||
|
char tmp[MAX_STR_SIZE];
|
||||||
|
snprintf(tmp, sizeof(tmp), ".%s", b_path);
|
||||||
|
strcpy(b_path, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(b_name, &b_path[si + 1]);
|
||||||
|
b_path[si + 1] = '\0';
|
||||||
|
int b_name_len = strlen(b_name);
|
||||||
|
|
||||||
|
DIR *dp = opendir(b_path);
|
||||||
|
|
||||||
|
if (dp == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char dirnames[MAX_DIRS][NAME_MAX];
|
||||||
|
struct dirent *entry;
|
||||||
|
int dircount = 0;
|
||||||
|
|
||||||
|
while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
|
||||||
|
if (strncmp(entry->d_name, b_name, b_name_len) == 0) {
|
||||||
|
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name);
|
||||||
|
++dircount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dircount == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (dircount > 1) {
|
||||||
|
execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < dircount; ++i)
|
||||||
|
line_info_add(self, NULL, NULL, NULL, dirnames[i], SYS_MSG, 0, 0);
|
||||||
|
|
||||||
|
complete_line(self->chatwin, dirnames, dircount, NAME_MAX);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return complete_line(self->chatwin, dirnames, dircount, NAME_MAX);
|
||||||
|
}
|
43
src/autocomplete.h
Normal file
43
src/autocomplete.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/* autocomplete.h
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Toxic All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This file is part of Toxic.
|
||||||
|
*
|
||||||
|
* Toxic is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Toxic is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _autocomplete_h
|
||||||
|
#define _autocomplete_h
|
||||||
|
|
||||||
|
/* looks for the first instance in list that begins with the last entered word in line according to pos,
|
||||||
|
then fills line with the complete word. e.g. "Hello jo" would complete the line
|
||||||
|
with "Hello john". Works slightly differently for directory paths with the same results.
|
||||||
|
|
||||||
|
list is a pointer to the list of strings being compared, n_items is the number of items
|
||||||
|
in the list, and size is the size of each item in the list.
|
||||||
|
|
||||||
|
Returns the difference between the old len and new len of line on success, -1 if error */
|
||||||
|
int complete_line(ChatContext *ctx, const void *list, int n_items, int size);
|
||||||
|
|
||||||
|
/* matches /sendfile "<incomplete-dir>" line to matching directories.
|
||||||
|
|
||||||
|
if only one match, auto-complete line and return diff between old len and new len.
|
||||||
|
return 0 if > 1 match and print out all the matches
|
||||||
|
return -1 if no matches */
|
||||||
|
int dir_match(ToxWindow *self, Tox *m, const wchar_t *line);
|
||||||
|
|
||||||
|
#endif /* #define _autocomplete_h */
|
28
src/chat.c
28
src/chat.c
@ -41,6 +41,7 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
|
#include "autocomplete.h"
|
||||||
|
|
||||||
#ifdef _SUPPORT_AUDIO
|
#ifdef _SUPPORT_AUDIO
|
||||||
#include "audio_call.h"
|
#include "audio_call.h"
|
||||||
@ -685,21 +686,22 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
input_handle(self, key, x, y, x2, y2);
|
input_handle(self, key, x, y, x2, y2);
|
||||||
|
|
||||||
if (key == '\t') { /* TAB key: auto-completes command */
|
if (key == '\t' && ctx->len > 1 && ctx->line[0] == '/') { /* TAB key: auto-complete */
|
||||||
if (ctx->len > 1 && ctx->line[0] == '/') {
|
int diff = -1;
|
||||||
int diff = complete_line(ctx, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
|
int sf_len = 11;
|
||||||
|
|
||||||
if (diff != -1) {
|
if (wcsncmp(ctx->line, L"/sendfile \"", sf_len) == 0) {
|
||||||
if (x + diff > x2 - 1) {
|
diff = dir_match(self, m, &ctx->line[sf_len]);
|
||||||
wmove(self->window, y, x + diff);
|
} else {
|
||||||
ctx->start += diff;
|
diff = complete_line(ctx, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
|
||||||
} else {
|
}
|
||||||
wmove(self->window, y, x + diff);
|
|
||||||
}
|
if (diff != -1) {
|
||||||
} else
|
if (x + diff > x2 - 1)
|
||||||
beep();
|
ctx->start += diff;
|
||||||
} else
|
} else {
|
||||||
beep();
|
beep();
|
||||||
|
}
|
||||||
|
|
||||||
} else if (key == '\n') {
|
} else if (key == '\n') {
|
||||||
rm_trailing_spaces_buf(ctx);
|
rm_trailing_spaces_buf(ctx);
|
||||||
|
@ -26,9 +26,9 @@
|
|||||||
#include <resolv.h>
|
#include <resolv.h>
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <arpa/nameser_compat.h>
|
#include <arpa/nameser_compat.h>
|
||||||
#else
|
#else
|
||||||
#include <arpa/nameser.h>
|
#include <arpa/nameser.h>
|
||||||
#endif /* ifdef __APPLE__ */
|
#endif /* ifdef __APPLE__ */
|
||||||
|
|
||||||
#include <tox/toxdns.h>
|
#include <tox/toxdns.h>
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
|
#include "autocomplete.h"
|
||||||
|
|
||||||
extern char *DATA_FILE;
|
extern char *DATA_FILE;
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
@ -247,7 +248,21 @@ int char_find(int idx, const char *s, char ch)
|
|||||||
{
|
{
|
||||||
int i = idx;
|
int i = idx;
|
||||||
|
|
||||||
for ( ; s[i]; ++i) {
|
for (i = idx; s[i]; ++i) {
|
||||||
|
if (s[i] == ch)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns index of the last instance of ch in s starting at len
|
||||||
|
returns 0 if char not found (skips 0th index) */
|
||||||
|
int char_rfind(const char *s, char ch, int len)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = len; i > 0; --i) {
|
||||||
if (s[i] == ch)
|
if (s[i] == ch)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -93,4 +93,8 @@ int get_nick_truncate(Tox *m, char *buf, int friendnum);
|
|||||||
returns length of s if char not found */
|
returns length of s if char not found */
|
||||||
int char_find(int idx, const char *s, char ch);
|
int char_find(int idx, const char *s, char ch);
|
||||||
|
|
||||||
|
/* returns index of the last instance of ch in s
|
||||||
|
returns 0 if char not found */
|
||||||
|
int char_rfind(const char *s, char ch, int len);
|
||||||
|
|
||||||
#endif /* #define _misc_tools_h */
|
#endif /* #define _misc_tools_h */
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
|
#include "autocomplete.h"
|
||||||
|
|
||||||
char pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE];
|
char pending_frnd_requests[MAX_FRIENDS_NUM][TOX_CLIENT_ID_SIZE];
|
||||||
uint16_t num_frnd_requests = 0;
|
uint16_t num_frnd_requests = 0;
|
||||||
|
@ -208,97 +208,3 @@ void fetch_hist_item(ChatContext *ctx, int key_dir)
|
|||||||
ctx->pos = h_len;
|
ctx->pos = h_len;
|
||||||
ctx->len = h_len;
|
ctx->len = h_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* looks for the first instance in list that begins with the last entered word in line according to pos,
|
|
||||||
then fills line with the complete word. e.g. "Hello jo" would complete the line
|
|
||||||
with "Hello john".
|
|
||||||
|
|
||||||
list is a pointer to the list of strings being compared, n_items is the number of items
|
|
||||||
in the list, and size is the size of each item in the list.
|
|
||||||
|
|
||||||
Returns the difference between the old len and new len of line on success, -1 if error */
|
|
||||||
int complete_line(ChatContext *ctx, const void *list, int n_items, int size)
|
|
||||||
{
|
|
||||||
if (ctx->pos <= 0 || ctx->len <= 0 || ctx->len >= MAX_STR_SIZE)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
const char *L = (char *) list;
|
|
||||||
|
|
||||||
char ubuf[MAX_STR_SIZE];
|
|
||||||
|
|
||||||
/* work with multibyte string copy of buf for simplicity */
|
|
||||||
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* isolate substring from space behind pos to pos */
|
|
||||||
char tmp[MAX_STR_SIZE];
|
|
||||||
snprintf(tmp, sizeof(tmp), "%s", ubuf);
|
|
||||||
tmp[ctx->pos] = '\0';
|
|
||||||
const char *s = strrchr(tmp, ' ');
|
|
||||||
int n_endchrs = 1; /* 1 = append space to end of match, 2 = append ": " */
|
|
||||||
|
|
||||||
char *sub = malloc(strlen(ubuf) + 1);
|
|
||||||
|
|
||||||
if (sub == NULL)
|
|
||||||
exit_toxic_err("failed in complete_line", FATALERR_MEMORY);
|
|
||||||
|
|
||||||
if (!s) {
|
|
||||||
strcpy(sub, tmp);
|
|
||||||
|
|
||||||
if (sub[0] != '/') /* make sure it's not a command */
|
|
||||||
n_endchrs = 2;
|
|
||||||
} else {
|
|
||||||
strcpy(sub, &s[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string_is_empty(sub)) {
|
|
||||||
free(sub);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int s_len = strlen(sub);
|
|
||||||
const char *match;
|
|
||||||
bool is_match = false;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* look for a match in list */
|
|
||||||
for (i = 0; i < n_items; ++i) {
|
|
||||||
match = &L[i * size];
|
|
||||||
|
|
||||||
if ((is_match = strncasecmp(match, sub, s_len) == 0))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(sub);
|
|
||||||
|
|
||||||
if (!is_match)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* put match in correct spot in buf and append endchars (space or ": ") */
|
|
||||||
const char *endchrs = n_endchrs == 1 ? " " : ": ";
|
|
||||||
int m_len = strlen(match);
|
|
||||||
int strt = ctx->pos - s_len;
|
|
||||||
int diff = m_len - s_len + n_endchrs;
|
|
||||||
|
|
||||||
if (ctx->len + diff > MAX_STR_SIZE)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
char tmpend[MAX_STR_SIZE];
|
|
||||||
strcpy(tmpend, &ubuf[ctx->pos]);
|
|
||||||
strcpy(&ubuf[strt], match);
|
|
||||||
strcpy(&ubuf[strt + m_len], endchrs);
|
|
||||||
strcpy(&ubuf[strt + m_len + n_endchrs], tmpend);
|
|
||||||
|
|
||||||
/* convert to widechar and copy back to original buf */
|
|
||||||
wchar_t newbuf[MAX_STR_SIZE];
|
|
||||||
|
|
||||||
if (mbs_to_wcs_buf(newbuf, ubuf, MAX_STR_SIZE) == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
wcscpy(ctx->line, newbuf);
|
|
||||||
|
|
||||||
ctx->len += diff;
|
|
||||||
ctx->pos += diff;
|
|
||||||
|
|
||||||
return diff;
|
|
||||||
}
|
|
||||||
|
@ -52,16 +52,6 @@ int yank_buf(ChatContext *ctx);
|
|||||||
/* Removes trailing spaces from line. */
|
/* Removes trailing spaces from line. */
|
||||||
void rm_trailing_spaces_buf(ChatContext *ctx);
|
void rm_trailing_spaces_buf(ChatContext *ctx);
|
||||||
|
|
||||||
/* looks for the first instance in list that begins with the last entered word in line according to pos,
|
|
||||||
then fills line with the complete word. e.g. "Hello jo" would complete the line
|
|
||||||
with "Hello john".
|
|
||||||
|
|
||||||
list is a pointer to the list of strings being compared, n_items is the number of items
|
|
||||||
in the list, and size is the size of each item in the list.
|
|
||||||
|
|
||||||
Returns the difference between the old len and new len of line on success, -1 if error */
|
|
||||||
int complete_line(ChatContext *ctx, const void *list, int n_items, int size);
|
|
||||||
|
|
||||||
/* adds a line to the ln_history buffer at hst_pos and sets hst_pos to last history item. */
|
/* adds a line to the ln_history buffer at hst_pos and sets hst_pos to last history item. */
|
||||||
void add_line_to_hist(ChatContext *ctx);
|
void add_line_to_hist(ChatContext *ctx);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user